Mikroracunari_skripta

Embed Size (px)

Citation preview

MIKRORACUNARISKRIPTA ZA SPREMANJE PISMENOG ISPITA

-1-

PredgovorOvo je skriptica koju sam pravio prilikom spremanja pismenog dela ispita iz Mikroracunara. U njoj nisam obradio SSE2 instrukcije, posto su one nadogradjene SSE instrukcije, a sve su lepo napisane u knjizi Ace Samardzica :) Srecno :) Viktor

-2-

Procesor (CPU - Central Processing Unit ili ISP - Instruction Set Processor) Osnovnu strukturu cpu-a mozemo podeliti na ALU i CU jedinicu. ALU obavlja obradu podataka dok CU kontrolise prenos podaka i instrukcija u i iz procesora. Savremeni mikroprocesori imaju i druge funkcionalne jedinice. Program se sastoji od masinskih instrukcija. Da bi se program izvrsio, procesor dohvata jednu po jednu instrukciju i izvrsava odgovarajucu operaciju. Procesor vodi o adresi memorijske lokacije koja sadrzi narednu instrukciju koja treba da se izvrsi pomocu PC (program counter) registra. Sadrzaj ovog registara se u toku izvrsenja tekuce instrukcije updejtuje da pokazuje na narednu instrukciju u nizu. Bitan je IR registar (instruction register) koji sadrzi poslednju procitanu instrukciju. Ako svaka instrukcija ima 4 bajta izvrsenje instrukcije izgleda : 1. dohvata se sadrzaj memorijske lokacije na koju pokazuje PC i ona se ucitava u IR IR [ESI + 4*ECX]Tipovi podataka IA32 uzima za operande vrednosti duzine 1, 2 , 4 , 8 ili 16 bajtova 1 - bytes 2 - words 4 - doublewords 8 - quadwords 16 - double quadwords tipovi podataka sa kojima procesor radi su neoznaceni i oznaceni celi brojevi, realni brojevi, pointeri, polja bitova, stringovi SIMID tipovi podataka, BCD brojevi.

-5-

Rad sa asemblerom Da bi koristili intelovu sintaksu koristimo direktivu na samom pocetku .intel_syntax noprefix noprefix- imena registara ne treba da imaju % prefiks koji asembler iance ocekuje Asemblerske direktive se ne prevode! One uticu na prevodjenje! Naredbe se razdvajaju novim redom ili dvotackom Komentari pocinju sa # Direktive : .data definise sekciju gde se deklarisu podaci cije vrednosti treba da budu inicijalizovane u memoriji. Svaka deklaracija se sastoji od tri dela ime_podatka: .tip_podatka vrednost .bss se koristi za neinicijalizovane podatke. Memorijske promenljive se u ovoj sekciji deklarisu pomocu .lcomm direktive koju slede zarezom razvojeni ime promenljive i broj bajtova koje ista u memoriji zauzima. .bss .lcomm x, 4 Direktiva .ascii .asciz .byte .double .float .int .octa .quad .short Tip podataka string string terminiran nulom 8 bitni ceo broj 64 bitni realan broj 32 bitni realan broj 32 bitni ceo broj 128 bitni ceo broj 64 bitni ceo broj 16 bitni ceo broj

.text - sekcija za kod .global main - oznacava da je simbol main vidljiv i izvan objektnog fajla. Simbol main oznacava pocetak programa.intel_syntax noprefix .data fmt: .asciz "Hello\n" .text .global main main: enter 0,0 pusha lea eax, fmt push eax call printf add esp, 4

Koristi se za raunanje efektivne adrese. scanf("%d",&x);

#stek raste prema nizim adresama pa zato ovako mozemo skinuti fmt sa #steka

popa xor eax, eax leave ret

Pri radu sa asemblerom treba voditi racuna da se argumenti prenose preko steka. Stek je deo memorije kome s e pristupa po LIFO principu, za rad sa njim koriste se PUSH i POP instrukcije. Prenosenje argumenata proceduri sastoji se od stavljanja istih na stek i to obrnutim redom! Kompajliranje : Fajlovi sa asemblerskim kodom imaju ekstenziju .s as - o hello.o hello.s gcc -o hello hello.o

-6-

Aritmeticko logicke instrukcije Instrukcije koje implementiraju binarne operacije najcesce upisuju rezultat u priv operand! Prvi operand zato ne moze biti konstanta! Samo jedan moze biti memorijski operand, drugi mora biti registar ili konstanta Menmonik ADD ADC SUB SBB INC DEC CMP NEG MUL Operacija sabiranje sabiranje sa prenosom oduzimanje oduzimanje sa pozajmicom inkrementiranje, kao i DEC radi sa jednim operandom dekrementiranje poredjenje, menja vrednosti flagova i nigde ne smesta rezultat, radi isto sto i SUB instrukcija promena znaka, tretira operan kao oznacen broj mnozenje neoznacenih brojeva ima samo jedan operand koji moze biti vrednost u registru ili u memroiji Ovaj operand se mnozi sa sadrzajem registra AL, AX ili EAX( u zavisnosti od sirine operanda), pri cemu rezultat biva smeste respektivno u registe AX, DX:AX odnosno EDX:EAX DX:AX - to znaci da se DX odnosi na vise bitove podataka a AX na nizemov eax, x imul dword ptr y push eax

Instrukcije imul i idiv prihvataju 8 bitni, 16 bitni i 32 bitni operand, kada se navodi vrednosti iz memorije njena sirina nije implicitno odredjena, pa se dodaje prefixBYTE PTR - 8-bitni operand WORD PTR - 16-bitni operand DWORD PTR - 32- bitni operand QWORD PTR - 64-bitni operand

IMUL DIV

mnozenje oznacenih brojeva deljenje neoznacenih brojeva ima samo jedan operand koji moze biti vrednost u registru ili u memroijimov eax, x cdq idiv dword ptr y push eax

Pri deljenju delilac se nalazi u EDX:EAX registrima. Zato treba registar EAX upisati u registar EDX. Za to koristimo CDQ instrukciju koja prosiruje 32bitnu vrednosu iz eax u 64bitnu u edx:eax registrima U registru EAX se nalazi celobrojni koicnika, a u EDX ostatak pri deljenju. Npr. ako delimo 23 sa 10, u eax se nalazi 2 a u edx 3 IDIV AND OR NOT XOR deljenje oznacenih brojeva bitska konjukcija bitska disjunkcija bitska negacija bitska operacija xor

-7-

Instrukcije za transfer podataka Menmonik MOV CMOV Operacija prenos podataka vazi sve kao i za binarne instrukcije- samo jedan moze biti memorijska lokacija uslovni prenos podataka uslov se tice flegova u EFLAGS registru sufiksi : Kao i kod instrukcija skokova, sto idu posle J podrzane od PentiumPro procesora razmena podataka razmenjuje sadrzaj svoja dva operanda promena redosleda bajtova razmena i sabiranje podataka prvo razmenjuje a onda izracunava zbir i smesta ga u odredisni operand testiranje i razmena podataka tri operanda porede dva operanda, pa ako su jednaki zamenjuju drugi sa trecim a ako nisu ucitavaju drugi u prvi radi sa 32 bitnim vrednostima prvi operand je implicitno EAX testiranje i razmena 64bitnih podataka tri operanda isto kao i cmpxchg radi sa 64bitnim operandima prvi i treci su implicitno refistri EDX:EAX odnosno ECX:EBX stavljanje na stek umanjuje esp za odgovarajuci broj i stavlja dati podatak na novu adresu na koju pokazuje ovaj registar skidanje sa steka uvecava vrednost esp registra stavljanje registara optse namene na stek skidanje registara opste namene sa steka koverzija 8bitne u 16bitnu vrednost AL->AX konverzija 16bitne u 32bitnu vrednost AX->DX:AX konverzija 16bitne u 32bitnu vrednost AX->EAX konverzija 32bitne u 64bitnu vrednost EAX->EDX:EAX prenos podataka uz prosirivanje ocuvanjem znaka prenos podataka uz prosirivanje popunjavanjem nulama

XCHG

BSWAP XADD

CMPXCHG

CMPXCHG8

PUSH

POP PUSHA POPA CBW

CWD

CWDE

CDQ

MOVSX MOVZX

-8-

Instrukcije kontrole toka Instrukcije bezuslovnog skoka: Mnemonik Operacija bezuslovni skok JMP ucitava u EIP registar adresu koja je zadata kao operan cime se izvrsavanje nastavlja instrukcijom koja se nalazi na toj adresi poziv potprograma CALL povratak iz potprograma RET Instrukcije uslovnog skoka : Proveravaju flegove u EFLAGS registru i vrse skok ako je dati uslov zadovoljen. Mnemonik Operacija JA/JNBE skok ako je vece JAE/JNB skok ako je vece ili jednako JB/JNAE skok ako je manje JBE/JNA skok ako je manje ili jednako skok ako ima prenosa JC skok ako je jednako JE/JZ Primer: poredimo da li je uneti karakter jednak znaku '+', znaci da prethodno sledi CMP radi proverecmp al, op je addition

JNC JNE/JNZ JP/JPE JNP/JPO JCXZ JECXZ JG/JNLE JGE/JNL JL/JNGE JLE/JNG JNO JNS JO JS

skok ako nema prenosa(jednako 0) skok ako nije jednako(razlicito od nule) skok ako je parnost parna skok ako je parnost neparna skok ako je registar CX jednak 0 skok ako je registar ECX jedna 0 Oznaceni brojevi skok ako je vece skok ako je vece ili jednako skok ako je manje skok ako je manje ili jednako skok ako nema prekoracenja skok ako je pozitivno skok ako ima prekoracenja skok ako je negativno

Instrukcije za brojacke petlje: Mnemonik Operacija Obicna instrukcija brojacke petlje LOOP Instrukcija LOOP dekrementira sadrzaj ECX registra i ukoliko nova vrednost nije jednaka 0, skace na adresu datu operandom. Petlje ovog tipa se izvrse bar jednom zato je pogodno koristiti naredbu JECXZ pa ako je brojac jednak 0 moze se preskociti citava petljanext: .... loop next:

LOOPE/LOOPZ LOOPNE/LOOPNZ

instrukcija brojacke petlje sa izlaskom ako ZF=0 instrukcija brojacke petlje sa izlasko ako ZF=1 Tekuci element je jednak trazenom

-9-

Instrukcije za rad sa stringovima String predstavlja kontinualan niz bitova, bajtova, wordova ili double word-ova. Instrukcije za rad sa stringovima imaju uglavnom implicitne operande. Adrese elemenata stringova koji ucestvuju u operaciji moraju biti u registrima ESI odnosno EDI. Velicina operanda je odredjena sufiksom instrukcije : B za 8bit, W za 16bit, D za 32bit. Po izvrsenju odgovarajuce operacije sadrzaj registra ESI i/ili EDI se azurira tako da pokazuju na naredni ili prethodni element stringa, sto je odredjeno vrednoscu direction flega u EFLAGS registru. Ako je on 0(CLD) onda se sadrzaj uvecava za odgovarajuci broj bajtova, ako je 1(STD) onda se umanjuje. Mnemonik Operacija kopiranje elemenata stringa MOVS poredjenje elemenata stringova CMPS poredjenja elemenata stringa sa datom vrednoscu SCAS Vrednost sa kojom se poredi tekuci element stringa nalazi se u AL, AX odn EAX refistru zavisno od sufiksa instrukcije ucitavanje elemenata stringa u registar, ucitava iz registra esi LODS smestanje sadrzaja registra u element stringa, ucitava u adresu koja se nalazi u registru edi STOS#poredi dva stringa .intel_syntax noprefix .data wrfmt: .asciz "%c\n" .bss .lcomm s0, 80 .lcomm s1, 80 .text .global main main: enter 0,0 pusha lea eax, s0 push eax call gets add esp, 4 lea eax, s1 push eax call gets add esp, 4 cld # duzina prvog stringa, string je terminiran # nulom, pa u al stavljamo 0 a u edi adresu # prvog karaktere u onda sa scas ispitujemo # redom dok ne nadjemo na nulu, Akumuliramo # duzinu u ecx xor al, al lea edi, s0 xor ecx, ecx next_char0: scasb je compare inc ecx jmp next_char0 compare: inc ecx #da bi ukljucili i termalni kar. lea esi, s0 lea edi, s1 #poredjenje stringova next_char1: cmpsb loope next_char1 # ako je petlja zavrsena jer su pronadjena dva # razlicita karaktera u al se smesta n a u # suprotnom se smesta y jme xor mov jmp not_equal: not_equal eax, eax al, 'y' print

xor eax, eax mov al, 'n' print: push eax lea eax, wrfmt push eax call printf add esp, 8 popa xor eax, eax leave ret

Instrukcije sa stringovima se cesto koriste u petljama zato IA32 podrzava prefikse koji se mogu njima dodati i omogucavaju da se petlje kompaktno zapisu. Ovde se isto kao i kod LOOP instrukcije dekrementira ECX registar. Prefiks Znacenje ponavljanje instrukcije sve dok je ECX razlicito od 0 REP ponavljanje sve dok je ECX razlicito od nule i ZF=0 REPE/REPZnext_char1: cmpsb = loopz next_char1 repz cmpsb

REPNE/REPNZ

ponavljanje sve dok su ECX i ZF razliciti od nule - 10 -

Instrukcije za rad sa flegovima Mnemonik STC CLC CMC STD CLD STI CLI LAHF SAHF PUSHF POPF PUSHFD POPFD Operacija postavlja carry fleg na 1 postavlja carry fleg na 0 komplemntiranje vrednosti carry flega postavlja direction fleg na 1 postavlja direction fleg na 0 postavlja interrupt fleg na 1 postavlja interrupt fleg na 0 ucitavanje bajta najmanje tezine EFLAGS registra u AH registar ucitavanje sadrzaja AH registra u bajt najmanje tezine EFLAGS registra stavljanje nizih 16 bitova EFLAGS registra na stek skidanje 16bitne vrednosti sa steka u nizih 16 bita EFLAGS registra stavljanje EFLAGS registra na stek skidanej 32bit vrednosti sa steka u EFLAGS registar

Preostale instrukcije opste namene Mnemonik LEA XLATB Operacija izracunavanje efektivne adrese date memorijske promenljive i smesta je u zadati registar opste namene instrukcija za lookup u tabeli Pristupa elementu polja bajtova u memoriji cija je adresa prvog elementa data u registru EBX a index elementa u AL, ucitava sadrzaj ovog elementa u AL insturkcija za detekciju procesora Pupunjava registre EAX,EBX,ECX, EDX sa informacijama o procesoru instrukcija koja ne radi nista samo uvecava sadrzaj EIP registra nedefinisana instrukcija

CPUID NOP UD2

Bitske instrukcije Mnemonik SHL/SAL SHR SAR SHLD SHRD ROL ROR RCL RCR BT BTS BTR BTC BSF BSR SET TEST Operacija logicko i aritmericko siftovanje ulevo logicko siftovanje udesno aritmeticko siftovanje udesno siftovanje ulevo iz drugog podatka siftovanje udesno iz drugog podatka rotacija ulevo rotacija udesno rotacija ulevo kroz CF rotacija udesno kroz CF testiranje bita testiranje i postavljanje bita na vrednost 1 testiranje i postavljanje bita na vrednost 0 testiranje i komplementiranje vrednosti bita pretrazivanje prema bitu najvece tezine pretrazivanje prema bitu najmanje tezine postavljanje bajta prema vrednosti flega bitska konjunkcija bez upisa rezultata

- 11 -

Potprogrami Potprogram po svom zavrsetku mora da zna da se vrati na instrukciju koja se nalazi iza instrukcije kojom je potprogram pozvan - > na IA32 cuva se povratna adresa na steku. CALL-> pre nego sto se skoci povratna adresa se stavlja na stek RET -> zavrsava se rad potprograma i skida se sa steka povratna adresa pa se bezuslovno skace na nju. RET ima forum u kojoj ima operand, a to je broj koji treba dodati na sadrzaj ESP registra(argumente koje prenosimo potprogramu) Argumenti se potprogramu prenose pomocu steka. Pre poziva potprograma argumenti se stavljaju na stek (samo 32bit vrednosti). Program im pristupa direktno. Problem : sto se ESP registar moze promeniti i tako da se argumenti ne mogu lako adresirati zato se standardno pristupa preko EBP u koji se odmah po ulasku stavlja na stek i u njega se kopira vrednost ESP registra, pa se stanje EBP registra vise ne menja, na kraju vracamo sadrzaj EBP regisra(tj skidamo ga sa steka - pogledati enter 0,0) Vracabhe rezultata se vrsi preko EAX registra..intel_syntax noprefix .data rdfmt: .asciz "%d" wrtfmt: .asciz "%d\n" .bss n: .int 1 .text .global main main: enter 0,0 pusha lea eax, n push eax lea eax, rdfmt push eax call scanf add esp, 8 mov eax, n push eax call fact push eax lea eax, wrtfmt push eax call printf add esp, 8 popa xor eax, eax leave ret fact: push ebp mov ebp, esp mov eax, [ebp+8] cmp eax ,1 jg recursion mov eax, 1 jmp done recursion : dec eax push eax call fact imul dword ptr [ebp+8] done : pop ebp ret 4

n povratna adresa EBP EBP stack framepravac rasta steka

Lokalne promenljive : na pocetku potprograma alociramo prostor za njih na steku tako sto od esp registra oduzmeom broj bajtova koji je potreban za njih, na kraju ne treba zaboraviti da treba dotai esp registur odgovarajuci broj bajtova. One postaju deo stack frame-a ENTER L, 0 zamenjuje sledecu sekvencu LEAVE zamenjuje sekvecu push ebp mov esp, ebp mov ebp, esp pop ebp sub esp, L - 12 -

Pozivanje asemblerskog i C koda C program stavlja argumente potprograma na stek i to pocev od poslednjeg argumenta prema prvome. Rezultat potprograma se vraca u registar EAX ili ST(0) Potprogrami moraju da ocuvaju sadrzaj registra EBX, ESI, EDI i EBP. Podebljani registri NE SMEJU da se menjaju, moraju biti ocuvani! Pozivanje funkcije za racunanje faktorijela iz prethodnog primera:main.c #include extern int fact(int); int main() { int n; scanf("%d", &n); printf("%d\n", fact(n)); return 0; } fact.s .intel_syntax noprefix .text .global fact fact: enter 8,0 mov ecx, [ebp+8] mov [ebp-4], dword ptr 1 mov [ebp-8], dword ptr 2 next: cmp [ebp-8],ecx jg done mov eax, [ebp-4] imul dword ptr [ebp-8] mov [ebp-4], eax inc dword ptr [ebp-8] jmp next done: mov eax, [ebp-4] leave ret

Makefile koji pokrece ovaj program treba da izgleda: fact: fact.o main.o gcc -o fact fact.o main.o fact.o: fact.s as -o fact.o fact.s main.o:main.c gcc -c -o main.o main.c Prenos pokazivaca kao argumenata funkcije: Neka se pokazivac nalazi na ebp+8 adresi na steku mov ebx, [ebp+8] # kopiramo podatak(pokazivac) sa adrese ebp+8 u registar ebx mov [ebx], # kopiramo zeljeni podatak na adresu na koju pokazuje ebx Prvo se mora iskopirati neki podatak iz memorije u registar, a zatim dereferencirati, jer se jedino mogu dereferencirati registri(sintaksa [ebx])

- 13 -

Rad sa realnim brojevimaRealni brojevi se predstavljaju nizom od 32 (single-precision) ili 64(double precision) bita. Bit najvece tezine je bit znaka i ima brednost 0 za pozitivne i 1 za negativne brojeva. Ostatak broja je podeljen na eksponent i mantisu. Ukoliko su bitovi eksponenta i mantise jednaki 0 onda je broj 0. Ukoliko su svi bitovi eksponenta jednaki 1, a mantisa jednaka 0, radi se o nizu bitova kojim se predtavljaju vrednosti plus i minus beskonacno. Na kraju ukoliko su svi bitovi eksponenta jednaki 1 a mantisa razlicita od nule, radi se o NaN vrednosti. Rad sa realnim brojevima u prvim verzijama 80386 kao i kod 80486 bio je izdvojen u numericki procesor. Sada je integrisan, ali se koristi naziv FPU(floating point unit). Registri numerickog koprocesora: Skup registara se sastoji od 8 registara za podatke duzine 80 bita (R0,...,R7), kontrolnog, statusnog i tag registra. Registri za podatke cuvaju brojeve u formatu sa prosirenom preciznoscu (15bitova za eksponent i 64 za mantisu). Oni se koriste kao stek! U statusnom registru jedno polje odredjuje koji je registar vrh steka. ST(0) ili ST- Vrh steka, a zatim redom ide ST(1), ST(2) Statusni registar sadrzi flegove koji ukazuju na to da li je doslo do greske. Kontrolni registar sadrzi bitove kojima se dozvoljava ili sprecava generisanje odgovarajuceg prekida ako dodje do greske prilikom izracunavanja, te preciznost... Tag registar opisuje sadrzaj registra za podatke (za svaki 2bita), tj da li je u registru nalazi validna vrednost, nula, specijalna vrednost ili je prazan. Instrukcije za transfer podataka Mnemonik FLD Operacija ucitavanje realnog broja iz memorije i smestanje na vrh steka za podatka. Operand moze biti u single DWORD PTR (float) double QWORD PTR (double) ili extended preciznosti Posle nje ST -> na ST(1) Moze imati kao operand i neki registar sa steka i tada se sadrzaj tog registra kopira na vrh steka. Isto tako i FST i FSTP ucitavanje celog broja iz memorije, u extended precisznosti upis realnog broja u memoriju, broj sa vrha steka upisuju na zadatu lokaciju upis celog broja u memoriju, broj sa vrha steka upisuju na zadatu lokaciju upis realnog broja u memoriju i njegovo skidanje sa steka upis celog broja u memoriju i njegovo skidanje sa steka razmenjuje sadrzaj registra sa vrha steka i registra koji se specificira kao operand prebacuje vrednost iz specificiranog registra u registar ST(0) ako je uslov ispunjen

FILD FST FIST FSTP FISTP FXCH FCMOV

Instrukcije za ucitavanje konstanti Mnemonik FLDZ FLD1 FLDPI FLDL2T FLDL2E FLDLG2 FLDLN2 Operacija Ucitavanje broja 0 Ucitavanje broja 1 Ucitavanje broja Ucitavanje broja log 2 10 Ucitavanje broja log 2 e Ucitavanje broja log10 2 Ucitavanje broja log e 2

Stavljaju novu vrednost na vrh steka! - 14 -

Rad sa realnim brojevima (2) Aritmeticke instrukcije

Mnemonik FADD/FADDP FIADD FSUB/FSUBP FISUB FSUBR/FSUBRP FMUL/FMULP FIMUL FDIV/FDIVP FIDIV FDIVR/FDIVPR FIDIVR FABS FCHS FSQRT FPREM FRNDINT FPREM1 FXTRACT FISUBR

Operacija Sabiranje realnih brojeva Sabiranje realnog i celog broja Oduzimanje realnih brojeva oduzimanje realnog i celog broja oduzimanje realnih brojeva sa obrnutim operandima mnozenje realnih brojeva mnozenje ralnog i celog broja deljenje realnih brojeva deljenje ralnog i celog broja deljenje realnih brojeva sa obrnutim operandima deljneje realnog i celog broja sa obrnutim operandima izracunavanje apsolutne vrednosti promena znaka operanda izracunavanje kvadratnog korena izracunavanje delimicnog ostatka zaokruzivanje na ceo broj zizracunavanje delimicnog ostatka po IEEE standardu razdvajanje eksponenta i mantise oduzimanje ralnog i celog broj sa obrnutim operandima

-Uzimaju za operande ili dva registra sa steka ili jedan registar i realan ili ceo broj iz memorije. -Instrukicije sa sufiksom P po izvrsenoj operaciji sikidaju vrednost sa vrha steka. -Kod instrukcija sa sufiksom R redosled operanada je obrnut

Primer na FADD instrukciji Prve dve varijante se odnose na 32bitni i 64bitni memorijski operand u kom slucaju se taj operand sabira sa vrednoscu reigstra ST(0) i rezultat se smesta na ST(0) Druge dve varijante imaju za operande registar ST(0) i neki drugi registar ST(i), pri cemu je u prvom slucaju prvi odredisni registar a u drugom je drugi odredisni registar. Postoje i dve varijante sa P prefiksom, prva ima dva operanda i to neki registar ST(i) kao odredisni operand a registar ST(0) kao drugi operand dok druga nema operande. U prvom slucaju se sabiraju vrednosti registra ST(i) i ST(0), rezultat se smesta u ST(i) i vrednost iz ST(0) se skida sa steka. U drugom operandi su implicitni i to ST(0) i ST(1) i rezultat se smesta u ST(1) a ST(0) se skida sa steka. FIADD postoji u dve varijante koje su ekvivalntne kao kod FADD.add: enter 0,0 # [ebp+8] a, [ebp+12] b fld dword ptr [ebp+8] fld dword ptr [ebp+12] faddp leave ret add: enter 0,0 # [ebp+8] a, [ebp+12] b fld dword ptr [ebp+8] fadd dword ptr [ebp+12] leave ret

- 15 -

Rad sa realnim brojevima (3)

Instrukcije poredjenja Mnemonik FCOM/FCOMP/FCOMPP Operacija predjenje realnih brojeva i podstavljanje flegova koprocesora Porede vrednost u registru ST(0) sa datim operandom, ako su operandi neuredjeni generise se greska. P skida jedan, a PP skida dva sa steka -One se mogu i koristiti za skidanje nepotrebnih vrednosti sa steka ( u istu svrhu se mogu koristiti i FFREE i FINCSTP instrukcije) isto kao prethodno uz neuredjeno poredjnje poredjenje realnih i celih brojeva i azuriranje flegova koprocesora isto kao i prethodno uz neurdjeno poredjnje poredjenje realnih brojeva uz azuriranje flagova u eflags registru poredjenje sa nulom klasifikacija broja klasifikacija vrednosti iz registra ST(0) u zavisnusti da li je obican realan broj, denormalizovan, nula, beskonacan ili NaN postavljaju se flegovi statusnog registra koprocesora

FUCOM/FUCOMP/FUCOMPP FICOM/FICOMP FUCOMI/FUCOMIP FCOMI/FCOMIP FTST FXAM

Neuredjeno poredjenje se odnosi ako jedan od brojeva ima NaN vrednost. Trigonometrijske instrukcije Mnemonik FSIN FCOS FSINCOS Operacija izracunavanje sinusa izracunavanje kosinusa istovremeno i sinus i kosinus zamenjuje sadrzaj registra na vrhu steka sa njegovim sinusom a potom stavlja na stek i vrednost njegovog kosinusa izracunavanje tangensa izracunavanje inverznog tangensa racuna inverzni tangens kolicnika registra st(1) i st(0) u radijanima i smesta u st(1) a potom skida vrednost sa vrha steka

FPTAN FPATAN

Sve uzimaju operande sa vrha registarskog steka i rezultat smestaju na isti. Operandi za prve cetiri instrukcije moraju biti zadati u radijanima. Logaritamske i eksponencijalne funckcije Mnemonik FYL2X Operacija izracunavanje vrednosti y log 2 x x, y se nalaze na registrima st(0) i st(1) rezultat se smesta u registar st(1) i skida se jedna vrednost sa steka izracunavanje vrednosti y log 2 ( x + 1) izracunavanje vrednosti 2 x 1 zamnejuje izracunatu vrednost iz registra st(0). Operand mora biti u opsegu [-1,1] mnozenje stepenom dvojke

FYL2XP1 F2XM1 FSCALE

- 16 -

Rad sa realnim brojevima (4) Kontrolne instrukcije Mnemonik FINIT/FNINIT Operacija inicijalizacija koprocesora inicijalizuju koprocesor i postavljaju sve njegove registre na podrazumevanje vrednosti ucitavanje kontrolnog registra korocesora FLDCW FSTCW/FNSTCW kopiranje sadrzaja kontrolnog registra koprocesora u memoriju FSTSW/FNSTSW kopiranje sadrzaja statusnog registra u memoriju resetovanje flagova u statusnom registru FCLEX/FNCLEX ucitavanje sadrzaja svih pomocnih registara koprocesora, osim steka iz memorije FLDENV FSTENV/FSTNENV kopiranje sadrzaja svih pomocnih registara koprocesora u memoriju ucitavanje sadrzaja svih registara koprocesora FRSTOR kopiranje sadrzaja svih registara procesora FSAVE/FNSAVE inkrementiranje stek-pointera za registarski stek FINCSTP dekrementiranje stek-pointera za registarski stek FDECSTP oslobadjanje registra FFREE prazna instrukcija FNOP instrukcija za sinhronizaciju WAIT/FWAIT

Ukoliko racunamo e na x, postupak je sledeci (najveci problem je kod F2XM1 , ona radi samo sa intervalom [-1,1]!!!). Koristimo :

e x = 2 log 2 e = 2 x log 2 ex

fld qword ptr [adresa od x] fldl2e fmulp #stek x*log2e=y fld st frndint # stek: y,int(y) fsub st(1),st fxch # int(y), y-int(y)=f f2xm1 #int(y), 2^f-1 fld1 faddp #int(y),2^f fscale #int (y),2^(f+int(y)) fxch fcomp

Koristan izraz koji jos koristimo :

n

r =2

log 2 ( n r )

=2

1 log 2 r n

- 17 -

Rad sa realnim brojevima (5).intel_syntax noprefix .data .text .global lnxplus1########################################################################### ## Funkcija: ## double lnxplus1(double x, double eps); ## racuna vrednost ln(x+1) kao parcijalnu sumu stepenog reda, sa ## preciznoscu eps. ## double x -- [ebp+8] -- broj ciji ln(x+1) racunamo ## double eps -- [ebp+16] -- preciznost ###########################################################################

lnxplus1:## Prolog funkcije

enter 0,0## ## ## ## Pripremamo fpu-stek, na koji smestamo 0 (kao inicijalnu vrednost sume), argumente funkcije (x i eps), a zatim i broj 1 (kao x^0, ovaj registar cemo u svakoj iteraciji mnoziti sa x, kako bismo dobili x^n).

fldz fld qword ptr [ebp+8] fld qword ptr [ebp+16] fld1 xor ecx,ecx## ## ## ## ##

## stek: ## ## ## stek:

0 stek: 0,x stek: 0,x,eps 0,x,eps,1

## Registar ecx ce cuvati celobrojnu vrednost n. Na pocetku svake ## iteracije cemo ga uvecavati za 1 (prvi sabirak je za n=1). Glavna petlja. U ovoj petlji racunamo sledeci sabirak, proveravamo da li je veci po apsolutnoj vrednosti od eps, i ako jeste, dodajemo ga na sumu. U komentarima nakon svake iteracije S je oznaka za sumu prvih n sabiraka, a S' je oznaka za sumu prvih n-1 sabiraka. Kada se n uveca za jedan, tada S postaje S'.

## stek: S,x,eps,x^n main_loop:## Uvecavamo n za jedan.

inc ecx## Racunamo x^n

## stek: S',x,eps,x^(n-1) ## stek: S',x,eps,x^n ## stek: S',x,eps,x^n,x^n

fmul st(0), st(2) fld st(0)## Racunamo x^n/n.

push ecx fidiv dword ptr [esp] add esp,4 fld st(0) fabs fcomip st, st(3) jb done

## stek: S',x,eps,x^n,x^n/n

## Ispitujemo da li je |x^n/n| < eps

## stek: S',x,eps,x^n,x^n/n,x^n/n ## stek: S',x,eps,x^n,x^n/n,|x^n/n| ## stek: S',x,eps,x^n,x^n/n

## Ako jeste, zavrsavamo petlju. ## Proveravamo da li je n parno ili neparno.

test ecx,1 jnz add## Za parno n, moramo da dodamo minus.

fchs add:

## stek: S',x,eps,x^n,-x^n/n

## Dodajemo sabirak na sumu, i prelazimo na sledecu iteraciju.

faddp st(4), st(0) jmp main_loop done:

## stek: S,x,eps,x^n ## stek: S,x,eps,x^n,x^n/n

## Skidamo sa fpu-steka sve vrednosti osim sume S.

fcompp fcompp## Epilog funkcije

## stek: S,x,eps ## stek: S

leave ret

- 18 -

Rad sa realnim brojevima (6).intel_syntax noprefix .text .global ctg_sum############################################################################ ## double ctg_sum(double x[], int n); ## racuna vrednost izraza: ## E = sum_{0 0) { ldrne r2, [r0], #4 @ S = S + *a++; addne r3, r3, r2 subne r1, r1, #1 @ n--; bne loop @ } mov r0, r3 @ return S; done: @ Epilog funkcije mov sp, fp ldmfd sp!, {fp, pc}

(2 nacin) sum: @ Prolog funkcije stmfd sp!, {fp, lr} mov fp, sp @ Postavljamo na stek vrednost registra r4 koji cemo koristiti @ u funkciji (registri r4-r10 moraju da se sacuvaju ako se @ koriste, po konvencijama). str r4, [sp, #-4]! @ Komentari u nastavku instrukcija priblizno opisuju njihove @ C-ovske ekvivalente. mov r2, #0 @ i = 0; mov r3, #0 @ S = 0; loop: cmp r2, r1 @ while(i < n) { bge end_loop ldr r4, [r0, r2, asl #2] @ S = S + a[i]; add r3, r3, r4 add r2, r2, #1 @ i = i + 1; b loop @ } end_loop: mov r0, r3 @ return S; done: @ Vracamo vrednost registra r4 sa steka. ldr r4, [sp], #4 @ Epilog funkcije mov sp, fp ldmfd sp!, {fp, pc}

- 31 -

ARM arhitektura (2)@ int fact(int n) -- r0 -- int n

fact: stmfd sp!, {fp,lr} mov fp, sp@ Smestamo na stek registar r4, jer cemo ga koristiti.

stmfd sp!, {r4}@ Cuvamo n u r4.

mov r4, r0 @ Izlaz iz rekurzije: fact(0)=1 cmp r0, #0 bne rec_call mov r0, #1 b done rec_call:@ Pozivamo fact(n-1)

sub r0, r0, #1 bl fact@ Mnozimo n * fact(n-1)

mov r2, r0 mul r0, r2, r4 done:@ Skidamo sa steka vrednost registra r4.

ldmfd sp!, {r4} mov sp, fp ldmfd sp!, {fp,pc}@ @ @ @ @ void minimax(int a[], int n, int * min, int * max); odredjuje najveci i najmanji element niza celih brojeva. Argumenti -- r0 -- int * a -- adresa pocetka niza -- r1 -- int n -- duzina niza -- r2 -- int * min -- adresa na koju se smesta minimum -- r3 -- int * max -- adresa na koju se smesta maksimum.

minimax: stmfd sp!, {fp, lr} mov fp, sp@ Smestamo na stek registre koje cemo koristiti.

stmfd sp!, {r4-r6}@ Registar r5 ce cuvati maksimum, a r4 minimum. Inicijalno su oba jednaka prvom elementu niza.

ldr r5, [r0], #4 mov r4, r5 sub r1, r1, #1 loop:@ Dokle god je n > 0

cmp r1, #0 beq end_loop@ Ucitavamo u r6 tekuci element niza, i pomeramo pokazivac a u desno.

ldr r6, [r0], #4@ Uporedjujemo ucitani element sa maksimumom.

cmp r6, r5@ Ako je vece, onda je to novi maksimum.

movgt r5, r6@ Uporedjujemo ucitani element sa minimumom.

cmp r6, r4@ Ako je manje, onda je to novi minimum.

movlt r4, r6@ Umanjujemo n i prelazimo na sledecu iteraciju.

sub r1, r1, #1 b loop end_loop:@ Cuvamo podatke na za to predvidjene lokacije.

str r4, [r2] str r5, [r3]@ Vracamo vrednosti registara koje smo koristili.

ldmfd sp!, {r4-r6} done: mov sp, fp ldmfd sp!, {fp, pc}

- 32 -

ARM arhitektura (3)@ int arm_strlen(char * s); @ izracunava duzinu stringa s. Argument funkcije je: @ r0 -- char * s -- adresa pocetka stringa arm_strlen: stmfd sp!, {fp, lr} mov fp, sp @ Registar r1 ce nam biti pokazivac na tekuci karakter u @ stringu. Registar r0 ce biti brojac karaktera u stringu. mov r1, r0 mov r0, #0 next_char: @ Ucitavamo neoznaceni bajt sa adrese r1 i pomeramo pokazivac u desno. ldrb r2, [r1], #1 @ Ako je dati karakter jednak nuli, izlazimo iz petlje, a u @ suprotnom uvecavamo brojac. cmp r2, #0 beq done add r0, r0, #1 b next_char @ Na kraju je u registru r0 duzina stringa, sto je upravo @ povratna vrednost funkcije. done: mov sp, fp ldmfd sp!, {fp, pc}

- 33 -

ARM arhitektura (4)@ void longest(char * str, int * start, int * length); @ pronalazi najduzu sekvencu istih karaktera u stringu. Argumenti funkcije su: @ -- r0 -- char * str -- adresa pocetka stringa @ -- r1 -- int * start -- lokacija na koju treba upisati indeks pocetka sekvence. @ -- r2 -- int * length -- lokacija na koju treba upisati duzinu sekvence. longest: stmfd sp!, {fp, lr} mov fp, sp stmfd sp!, {r4-r8} mov r4, #0 @ Registar r4 cuva pocetni indeks do sada najduze sekvence mov r5, #0 @ Registar r5 cuva duzinu do sada najduze sekvence. @ Ucitavamo prvi karakter i proveravamo da li je nula. ldrb r3, [r0], #1 cmp r3, #0 beq store mov r6, #0 @ Registar r6 cuva indeks pocetka tekuce sekvence. mov r7, #1 @ Registar r7 cuva tekucu duzinu sekvence. mov r8, r3 @ Registar r8 cuva prethodni karakter. next_char: @ Ucitavamo sledeci karakter i proveravamo da li je nula. ldrb r3, [r0], #1 cmp r3, #0 beq last_char @ Uporedjujemo tekuci karakter sa prethodnim. cmp r8, r3 beq equal @ Ako su razliciti, to je kraj tekuce sekvence. U tom slucaju @ poredimo duzinu tekuce sekvence sa do sada najduzom. cmp r7, r5 ble skip @ Ako je tekuca sekvenca duza, tada se azuriraju informacije @ o najduzoj sekvenci. mov r4, r6 mov r5, r7 skip: @ Inicijalizujemo sledecu sekvencu. add r6, r6, r7 mov r7, #1 b continue equal: @ Ako su tekuci i prethodni karakter jednaki, uvecavamo duzinu @ tekuce sekvence. add r7, r7, #1 continue: @ Tekuci postaje prethodni i prelazimo na sledeci karakter. mov r8, r3 b next_char last_char: @ Proveravamo da li je mozda poslednja sekvenca najduza. cmp r7, r5 ble store mov r4, r6 mov r5, r7 store: @ Cuvamo vrednosti u za to predvidjene lokacije. str r4, [r1] str r5, [r2] ldmfd sp!, {r4-r8} done: mov sp, fp ldmfd sp!, {fp, pc}

- 34 -

ARM arhitektura (5)@ Funkcija: @ @ int twobits(unsigned x); @ @ izracunava broj pojavljivanja dve uzastopne jedinice u binarnom zapisu @ broja x. Argument funkcije je: @ @ -- r0 -- unsigned x -- dati broj @ twobits: @ Prolog funkcije stmfd sp!, {fp, lr} mov fp, sp @ Ideja algoritma: ako je binarni zapis datog broja dat kao @ x[31],x[30]...x[1],x[0], gde je x[i] bit na poziciji i u broju, @ tada se pomeranjem u desno za jednu poziciju dobija vrednost @ 0,x[31],x[30]...x[1]. Ako sada izvrsimo bitovsku konjukciju @ dobijene i originalne vrednosti, dobijamo vrednost: @ 0,(x[30]&x[31]),(x[29]&x[30]),...,(x[0]&x[1]). Broj jedinica @ u ovom binarnom zapisu je upravo jednak broju uzastopnih @ parova jedinica u originalnom broju. @ Kopiramo r0 u r3 mov r3, r0 @ Pomeramo r3 za jednu poziciju u desno (logicki) mov r3, r3, lsr #1 @ Vrsimo logicku konjukciju r0 i r3. and r0, r0, r3 @ Registar r1 ce biti brojac jedinica. Inicijalizujemo ga nulom. mov r1, #0 @ U registar r2 smestamo masku cija je vrednost inicijalno @ 1000...0000 mov r2, #1 mov r2, r2, lsl #31 next_bit: @ Dok maska ne postane nula cmp r2, #0 beq last_bit @ Testiramo bit tst r0, r2 @ Ako je jedan, uvecavamo brojac jedinica. addne r1, r1, #1 @ Pomeramo masku za jednu poziciju u desno. mov r2, r2, lsr #1 b next_bit last_bit: @ Smestamo rezultat u r0 mov r0, r1 @ Epilog funkcije mov sp, fp ldmfd sp!, {fp, pc}

- 35 -