Uvod:

Intel-ova 32-bitna arhitektura (uobicajena oznaka je IA-32) je najcesce
koriscena arhitektura procesora na danasnjim PC racunarima. Ona obuhvata 
sve Intel-ove procesore pocev od procesora 386, zatim 486, Pentium I, 
Pentium Pro, Pentium MMX Pentium II, Pentuim III, Pentium IV, kao i novije 
modele sa vise jezgara (Pentium Dual Core, Intel Core 2 Duo, itd.). Takodje, 
AMD ekvivalentni procesori (AMD k5, AMD k6, AMD k6-2, AMD k7, AMD Athlon, 
AMD Sempron, AMD Duron, itd.) takodje implementiraju IA-32 arhitekturu.

Registri:

IA-32 arhitektura ima 8 32-bitnih registara: EAX, EBX, ECX, EDX, ESI, 
EDI, ESP, EBP. Ovi registri su generalno opste namene, mada u praksi 
neki imaju specijalne uloge. Tako na primer, ESP se uvek koristi kao 
pokazivac vrha sistemskog steka, EBP je pokazivac tekuceg okvira steka. 
Ostali registri u nekim situacijama mogu imati specijalne uloge (npr. 
pri mnozenju i deljenju se uvek implicitno koriste registri EAX i EDX, 
dok se pri radu sa stringovima za pokazivace uvek koriste registri ESI 
i EDI).

Vrste operanada i adresiranje:

-- Registarski operandi -- koristi se vrednost iz registra koji je naveden 
                           kao operand.
-- Neposredni operandi -- koristi se vrednost konstante koja se navodi kao 
                          operand.
-- Memorijski operandi -- koristi se vrednost iz memorije na adresi koja se 
                          zadaje kao operand.

Instrukcija moze imati najvise jedan memorijski operand. Prvi operand 
instrukcije je uvek odredisni operand, i ne moze biti konstanta.

Zadavanje memorijskog operanda:

Najjednostavniji nacin zadavanja memorijskog operanda je navodjenjem 
odgovarajuce labele. U opstem slucaju, adresa se moze zadati na slozeniji 
nacin, a opsti oblik je dat formulom:

           bazna_adresa + faktor * indeks + pomeraj
		      
gde je bazna adresa uvek sadzana u nekom registru, faktor je konstanta 
1, 2, 4, ili 8 (ako se ne navede podrazumeva se 1), indeks je takodje 
uvek u nekom registru, a pomeraj je konstanta. Ovaj izraz se uvek navodi 
u zagradama [] prilikom navodjenja u asembleru. Svaka od komponenti se moze 
izostaviti. Tako, ako se navede samo bazna adresa, to se zove "bazno 
adresiranje" (u registru imamo pokazivac koji "dereferenciramo" i dobijamo 
podatak sa te adrese). Ako se navede bazna adresa i indeks (pomnozen nekim 
faktorom) to se zove "indeksno adresiranje". Ono je zgodno prilikom rada sa 
nizovima: u bazni registar se smesti adresa pocetka niza, a u indeksni 
registar se smesti tekuci indeks (koji se azurira u svakoj iteraciji). Za 
faktor se uzima velicina elementa niza. Primeri:

mov eax, [esi] ## Premesta u eax vrednost sa adrese na koju pokazuje 
               ## esi (bazno adresiranje)
add ecx, [ebx + 4] ## Dodaje se na ecx vrednost sa adrese ebx + 4 (bazna 
                   ## adresa + pomeraj)
mov eax, [ebx + 4 * ecx] ## U eax se kopira vrednost sa adrese ebx + 4 * ecx 
                         ## (indeksno adresiranje,
                         ## pri cemu je bazna adresa (adresa pocetka niza) 
			 ## u registru ebx, a indeks se nalazi u registru 
			 ## ecx. Koristi se faktor 4, tj. elementi niza su 
			 ## velicine 4 bajta, npr. niz int-ova).
sub [edi + 4 * ecx + 4], eax ## Najslozeniji oblik, sadrzi sve komponente. 
    	                     ## Pomeraj je 4 bajta, bazna adresa se nalazi 
                             ## u edi, indeks u ecx, a faktor skaliranja je 4. 
			     ## Vrednost na ovoj lokaciji se umanjuje za 
                             ## vrednost registra eax.
cmp edi, [esi + ecx]    ## Indeksno adresiranje -- bazni registar je u 
                        ## registru esi, indeks u ecx, faktor je podrazumevano 
                        ## 1, nema pomeraja. Adresa se prosto izracunava kao 
                        ## zbir bazne adrese i indeksa. Uporedjuje se registar 
                        ## edi sa podatkom na adresi esi + ecx.

U slucaju da instrukcija koja sadrzi memorijski operand nema ni jedan 
registarski operand, tada se mora eksplicitno spcificirati sirina memorijskog
operanda. Ovo se radi navodjenjem jednog od prefiksa:

-- byte ptr -- za jednobajtni podatak
-- word ptr -- za dvobajtni podatak
-- dword ptr -- za cetvorobajtni podatak (mi cemo pretezno koristiti ovaj prefiks)

Na primer:

inc dword ptr [esi]  ## uvecava cetvorobajtnu vrednost na adresi na koju
    	             ## pokazuje esi

push dword ptr L     ## potiskuje na stek cetvorobajtni podatak sa adrese
                     ## koja je pridruzena labeli L.

Ovo nije neophodno ako registarski operand postoji u instrukciji, zato
sto onda njegova sirina implicitno odredjuje sirinu operanada koji se koriste.

Instrukcija transfera:
-- MOV op1, op2  -- premestanje (op1 = op2) 
-- LEA op1, op2 -- ucitavanje adrese, pri cemu je drugi operand uvek memorijski
                   operand.

Aritmeticko logicke instrukcije:
-- ADD op1, op2 -- sabiranje (op1 = op1 + op2)
-- SUB op1, op2 -- oduzimanje (op1 = op1 - op2) 
-- AND op1, op2 -- bitovska logicka konjukcija (op1 = op1 & op2) 
-- OR op1, op2 -- bitovska logicka disjunkcija (op1 = op1 | op2)
-- XOR op1, op2 -- bitovska logicka ekskluzivna disjunkcija (op1 = op1 ^ op2)
-- NOT op -- bitovska negacija (op = ~op)
-- MUL op  -- mnozenje neoznacenih celih brojeva (edx:eax = eax * op)
-- IMUL op  -- mnozenje oznacenih celih brojeva (edx:eax = eax * op)
-- DIV op -- deljenje neoznacenih celih brojeva 
             (eax = edx:eax / op, edx = edx:eax % op)
-- IDIV op -- deljenje oznacenih celih brojeva 
             (eax = edx:eax / op, edx = edx:eax % op)
-- NEG op -- promena znaka (op = -op)
-- INC op -- uvecanje (op = op + 1)
-- DEC op -- umanjenje (op = op - 1)
-- SHL op1, op2 -- shift-ovanje ulevo (op1 = op1 << op2). op2 je konstanta.
-- SHR op1, op2 -- shift-ovanje udesno (logicko) (op1 = op1 >> op2). 
       	    op2 je konstanta.
-- SAR op1, op2 -- shift-ovanje udesno (aritmeticko) (op1 = op1 >> op2). 
       	    op2 je konstanta.

Oznaka edx:eax znaci 64-bitni ceo broj ciji su visi bitovi u edx a nizi u eax.



Instrukcije poredjenja:
-- CMP -- uporedjivanje (oduzimanje bez upisivanja rezultata) 
-- TEST -- testiranje bitova (bitovska konjukcija bez upisivanja rezultata)

Instrukcije za rad sa stekom:

-- PUSH op  -- postavljanje na stek (sub esp, 4 ; mov [esp], op)
-- POP op   -- skidanje sa steka (mov op, [esp] ; add esp, 4)
-- PUSHA    -- postavlja sve registre opste namene na stek
-- POPA     -- skida sa steka 8 vrednosti i smesta ih u registre opste namene)

Zbog efikasnosti, na stek uvek treba postavljati 32-bitne vrednosti.

Instrukcije kontrole toka:

-- JMP op -- bezuslovni skok na adresu op (memorijski operand)
-- CALL op -- bezuslovni skok uz pamcenje povratne adrese na steku.
-- RET     -- skida sa steka adresu i skace na tu adresu.
-- JZ  op -- skace ako je rezultat prethodne instrukcije nula.
-- JE op   -- skace ako je rezultat prethodnog poredjenja jednakost 
              (ekvivalentno sa JZ)
-- JNZ op  -- skace ako je rezultat prethodne operacije razlicit od nule
-- JNE op  -- skace ako je rezultat prethodnog poredjenja razlicitost 
              (ekvivalentno sa JNZ)
-- JA op   -- skace ako je rezultat prethodnog poredjenja vece 
              (neoznaceni brojevi)
-- JB op   -- skace ako je rezultat prethodnog poredjenja manje 
              (neoznaceni brojevi)
-- JAE op  -- skace ako je rezultat prethodnog poredjenja vece ili jednako 
              (neoznaceni brojevi)
-- JBE op  -- skace ako je rezultat prethodnog poredjenja manje ili jednako 
              (neoznaceni brojevi)
-- JG op  --  skace ako je rezultat prethodnog poredjenja vece 
              (oznaceni brojevi)
-- JL op  --  skace ako je rezultat prethodnog poredjenja manje 
              (oznaceni brojevi)
-- JGE op  -- skace ako je rezultat prethodnog poredjenja vece ili jednako 
              (oznaceni brojevi)
-- JLE op  -- skace ako je rezultat prethodnog poredjenja manje ili jednako 
              (oznaceni brojevi)

Slicno, postoje i negacije gornjih instrukcija uslovnog skoka: JNA, JNB, JNAE, 
JNBE, JNG, JNL, JNGE, JNLE.

Instrukcije koje se koriste u prologu i epilogu funkcije:

-- ENTER N, 0 je ekvivalentno sa:

push ebp
mov ebp, esp
sub esp, N

-- LEAVE je ekvivalentno sa:

mov esp, ebp
pop ebp

Konvencije o pozivanju C-funkcija:

-- registri ESI, EDI i EBX pripadaju pozivajucoj funkciji. Pozvana funkcija 
   mora sacuvati na steku njihove vrednosti, ako ih koristi. Pozivajuca 
   funkcija moze racunati na vrednosti ovih registara, nezavisno od poziva 
   drugih funkcija.
   
-- registri EAX, ECX i EDX pripadaju pozvanoj funkciji. Pozvana funkcija ne 
   mora cuvati njihove vrednosti. Pozivajuca funkcija ne sme racunati da se 
   njihove vrednosti nece promeniti prilikom poziva drugih funkcija.
   
-- argumenti se prenose preko steka, tako sto pozivajuca funkcija na stek 
   postavlja argumente u obrnutom poretku (sa desna na levo). Pozivajuca 
   funkcija je takodje odgovorna za njihovo uklanjanje sa steka nakon povratka 
   iz pozvane funkcije.
   
-- Povratna vrednost se ostavlja u registru EAX. 

O GNU asembleru (as program):

-- Komentari pocinju znakom #. Sve do kraja linije se ignorise.
-- Direktive asemblera pocinju tackom. Neke cesto koriscene direktive:

.intel_syntax noprefix  -- oznacava da se koristi Intel-ova sintaksa.
.text -- oznacava pocetak zone sa tekstom.
.data -- oznacava pocetak zone sa statickim podacima.
.int n -- emituje u objektni fajl ceo broj n
.asciz str -- emituje u objektni fajl bajtove karaktera iz kojih se sastoji 
              string str, kao i terminirajucu nulu.
.global label -- oznacava labelu kao globalnu, cime se omogucava linker-u da
                 poveze 

-- Ostale linije koje nisu direktive se smatraju instrukcijama. Instrukcije
se sastoje iz mnemonika i zarezima razdvojenih operanada.

-- Svaka linija moze pocinjati labelom -- identifikatorom za kojim sledi
dvotacka. Svakoj labeli se u fazi prevodjenja dodeljuje adresa instrukcije
ili podatka koji sledi neposredno nakon labele u kodu. Labele se kasnije
mogu koristiti kao memorijski operandi (npr. add ecx, L, ili jmp L, gde je
L neka labela).

-- Prazne linije se ignorisu.

Prevodjenje:

Izvorni kod sa asemblerskim funkcijama se prevodi na sledeci nacin:

as -o asm.o asm.s

Gde se 'asm' treba zameniti nazivom konkretnog fajla. Uobicajeno je
da se fajlovima sa asemblerskim kodom daje ekstenzija .s

Izvorni kod sa C funkcijama se prevodi na sledeci nacin:

gcc -c -o c_func.o c_func.c

gde 'c_func' treba zameniti odgovarajucim imenom fajla. Opcija -c govori
prevodiocu da ne pokusava link-ovanje, vec da se zaustavi na kreiranju
odgovarajuceg objektnog fajla.

Povezivanje (link-ovanje) se vrsi na sledeci nacin:

gcc -o test c_func.o asm.o

gde opet treba uzeti odgovarajuca imena fajlova. Izvrsni fajl ce se zvati
'test' (i ovo se moze birati po zelji).

Za sve nejasnoce, obratiti se na mail: milan [at] matf.bg.ac.rs
