Assembler

**Assembler** on kompilaator, mis võimaldab tõlkida assemblerkeeles kirjutatud programmi masinkoodiks. Assembler võimaldab suhelda otse arvuti riistvaraga, tõlkides inimesele arusaadavad juhised masinkoodiks, mida arvuti protsessor saab otse täita. 

Assemblerid on tihedalt seotud arvuti riistvara arhitektuuriga, millele need peavad tõlkima koodi. Erinevad arhitektuurid (nagu x86, ARM jne) kasutavad erinevaid käskude komplekte. Seega peavad assemblerid olema kohandatud vastavalt konkreetsele arhitektuurile, millele need on mõeldud. Näiteks assembler, mis on mõeldud x86 arhitektuuri jaoks, ei pruugi olla ühilduv ARM arhitektuuriga ja vastupidi. 

Assembleri kasutatakse laialdaselt tarkvaraarenduses, kus tuleb luua tarkvara, mis suhtleb otse arvuti riistvaraga. Sellised rakendused hõlmavad operatsioonisüsteeme, draivereid ja muid tarkvarakomponente, mis peavad täitma madalal tasemel ülesandeid, nagu mälu haldamine, riistvara juhtimine ja protsessori käskude täitmine. 

Lisaks kasutatakse assembleri mikrokontrollerite programmeerimisel, kus tarkvara peab suhtlema väikeste, spetsialiseeritud arvutisüsteemidega. Sellistes rakendustes on assemblerikeel sageli eelistatud valik, kuna see on kiire ja võimaldab täpset kontrolli riistvara üle.

Vahel kasutatakse sõna "assembler" kõnekeeles ka assemblerkeele kohta. 

## Ajalugu

Esimene assemblerikeeles kirjutatud kood, milles kasutati sõnu masinkoodi juhiste kirjeldamiseks leidub Kathleen ja Andrew Boothi töös "Coding for A.R.C." aastast 1947. Assemblerikeelne kood muudeti käivitatavaks masinkoodiks programmi abil, mida nimetati assembleriks. 

Sõna "assembler" omistatakse üldiselt Wheelerile, Wilkesile ja Gillile nende 1951. aasta raamatus "The Preparation of Programs for an Electronic Digital Computer", kus seda kasutati tähenduses "programm, mis koostab teise mitmest osast koosneva programmi üheks programmiks", kus programmi koostamise protsessi kutsuti assembleerimiseks (*assembly*). 

Assemblerid on olnud saadaval alates 1950. aastatest, olles masinkeele ja kõrgkeelte vahel. Assemblerite kasutuselevõtt avas tee kõrgtasemel programmeerimiskeeltele nagu Fortran, Algol, COBOL, Lisp jne. 

Enne assemblereid pidid programmeerijad käsitsi “kirjutama” masinkoodi, mis koosnesid arvukatest binaarsetest instruktsioonidest ja mäluaadressidest. See protsess oli aeganõudev, vigade rohke ning nõudis sügavat arusaamist arvuti riistvarast. Assemblerite kasutuselevõtt automatiseeris ja lihtsustas seda protsessi oluliselt. 
## Tööpõhimõte

### Assemblerkeele põhimõtted
Assembleri keel koosneb lühikestest mnemoonilistest koodidest ja sümbolitest, mis määravad käskude, andmete ja struktuuride paigutuse. Assembleri keeles kirjutatud programm koosneb tavaliselt mitmest osast.

# **Muutujate osa** – see sektsioon võib sisaldada muutujate või andmestruktuuride defineerimist, mida programm kasutab. Siin võivad olla määratletud sümbolid, mis tähistavad muutujate või andmestruktuuride algust. Selle osa eesmärk on lihtsustada muutujatele või andmestruktuuridele juurdepääsu programmi teistes osades.
# **Andmete ja konstantide osa** – see sisaldab püsivaid andmeid või konstante, mida programm kasutab. Siin võivad olla määratletud näiteks sõned, täisarvud või muud konstantsed andmed, mida programm kasutab oma tööks.
# **Käskude osa** – see on programmikoodi põhiosa, kus asuvad assemblerikeelsed instruktsioonid. Iga käsk koosneb tavaliselt mnemoonikast (nt MOV, ADD, JMP), millele järgneb üks või mitu operandi (nt registrid, mäluaadressid või konstandid).

#### Assemblerkeele näide

```asm
; -----------------------------------------------------------------------
; hello.asm
;
; See on Win32 konsooliprogramm, mis kirjutab ühele reale "Hello, world"
; ning seejärel lõpetab. See kasutab ainult Win32 süsteemi kutsungeid
; kernel32.dll-st
; -----------------------------------------------------------------------

        .386P
        .model    flat
        extern    _ExitProcess@4:near
        extern    _GetStdHandle@4:near
        extern    _WriteConsoleA@20:near
        public    _go

        .data
msg     byte      'Hello, World', 10
handle  dword     ?
written dword     ?

        .stack

        .code
_go:        
        ; handle = GetStdHandle(-11)
        push      -11
        call      _GetStdHandle@4
        mov       handle, eax

        ; WriteConsole(handle, &msg[0], 13, &written, 0)
        push      0
        push      offset written
        push      13
        push      offset msg
        push      handle
        call      _WriteConsoleA@20

        ; ExitProcess(0)
        push      0
        call      _ExitProcess@4

        end
```


### Assembleri põhimõtted/töökäik
Assembler tõlgib assemblerkeeles kirjutatud programmi masinkoodiks. See protsess hõlmab mitmeid samme:

# **Leksikaalne analüüs** – assembler võtab sisendina assemblerkeeles kirjutatud koodi ja analüüsib seda, teisendades selle "tokeniteks". Need tokenid võivad hõlmata käskusid, registreid, mäluaadresse, konstante jne.
# **Süntaksi analüüs** – järgmise sammuna kontrollib assembler, kas tokenid järgivad assemblerkeele süntaksi reegleid. See hõlmab kontrollimist, kas kõikidel kasutatud käskudel on õige vorm ja kas kõik sulud, komad jne on korrektselt paigutatud.
# **Semantiline analüüs** – assembler kontrollib, kas koodi semantika on korrektne, st kas kood teeb mõistlikult midagi. See hõlmab muu hulgas kontrollimist, kas kasutatud registrid ja mäluaadressid on sobivad ning kas juhised on korrektselt koostatud.
# ***Optimeerimine** – mõned assemblerid võivad teha mõningaid optimeerimisi, et muuta genereeritud masinkood efektiivsemaks. Näiteks võib see hõlmata käskude ümberkorraldamist või mõne liigse operatsiooni eemaldamist.
# **Koodi genereerimine** – assembler genereerib masinkoodi, mis on arvuti poolt otse käivitatav.
# ***Linkimine** – linkimine võib olla vajalik, kui programm koosneb mitmest osast või kasutab väliseid funktsioone või raamatukogusid. Linkimine on protsess, kus mitu masinkoodifaili või välised raamatukogud ühendatakse üheks käivitatavaks programmiks.

Optimeerimist ja Linkimist ei tehta/kasutata alati assembleri tööprotsessis, see sõltub konkreetsest assemblerist ja programmist.

#### Masinkoodi näide

```mips
01010101 10001001 11100101 10000011 11100100 11110000 10000011 11101100 00010000 11000111 00000100 00100100 11010100 10000100 00000100 00001000 11101000 10111011 11111110 11111111 11111111 10111000 00000000 00000000 00000000 00000000 11001001 11000011 01100110 10010000 01100110 10010000
```


## Vaata ka
*GNU Binutils
*x86 assembler

## Viited