1k likes | 1.38k Views
X86 asembler. 80 386 procesor. 32 -bitna CISC arhitrktura . Pretežno dvoadresna mašina. Veličina memorijskog adresnog prostora: 4GB. Adresibilna jedinica: bajt. Veličina podataka u instrukcijama: bajt, reč ( word )– dva uzastopna bajta,
E N D
80386 procesor • 32-bitna CISC arhitrktura. • Pretežno dvoadresna mašina. • Veličina memorijskog adresnog prostora: 4GB. • Adresibilna jedinica: bajt. • Veličina podataka u instrukcijama: • bajt, • reč (word)– dva uzastopna bajta, • dvostruka reč (doubleword) – četiri uzastopna bajta.
Redosled bajtova podatka u memoriji • Little-endian – viši bajt na višoj adresi. • Riječi: • (a): 34 12 • (a+1): 56 34 • (a+2): 78 56 • Duple riječi: • (a) : 78 56 34 12
Zdravo svete! (Linux, int) 3 • .intel_syntax noprefix.arch i386.data1poruka:.ascii “Zdravo svete!\n“kraj_poruke:.equ duzina_poruke, kraj_poruke – poruka.text1 • .globl _start_start:mov ebx, 1# mov ecx, offset porukalea ecx, porukamov edx, duzina_porukemov eax, 4int 0x80 2mov ebx,0mov eax,1int 0x80 2
Prevođenje, povezivanje i pokretanje • Asembliranje: • as zdravo_svete.s –o zdravo_svete.o • korišćena opcija: -o <output_file_name> • Linkovanje (povezivanje): • ld zdravo_svete.o –o zdravo_svete • korišćena opcija: -o <output_file_name> • Pokretanje • ./zdravo_svete
Prevođenje i povezivanje pomoću gcc • Asembliranje: gcc -c -o zdravo_svete.o zdravo_svete.s • korišćene opcije: • -o <output_file_name> • -c Prevedođenje i asembliranje, bez linkovanja • Linkovanje (povezivanje): gcc -o zdravo_svete -nostartfiles zdravo_svete.o • korišćene opcije: -o <output_file_name> -nostartfilesPoveži bez standardnih startup fajlova. • Ili, i prevođenje i povezivanje jednim pozivom gcc: gcc -o zdravo_svete -nostartfiles zdravo_svete.s • Druge opcije: -nodefoultlibs Povezivanje bez standardnih biblioteka. -nostdlib Kao –nostartfiles –nodefaultlibs -v Ispisuje komande koje pokreće. -### Kao prethodno, ali bez izvršavanja komandi.
Asemblerske naredbe (Intel sintaksa) • [labela:]mnemonik[operandi] [#komentar] • Labela predstavlja adresu na kojoj se nalazi naredba. • mnemonik je simbolički zapisana komanda. • Mogu biti do dva operanda. • Prvi je uvijek odredište, a nekad i izvorište. • Drugi je izvorište.
Transfer podataka • mov dst, src # dst = src • lea dst, src # dst = offset(src)1 • lds dst, src # ds:dst = src • les dst, src # es:dst = src • xchg op1, op2 # mijenja vrijednosti # u operandima op1 i op2
Programski dostupniregistri(flat mode, aplikativni režim) • Opštenamjenski (32-bitni): • eax, ebx, ecx,edx, esiiedi. • Registri za manipulaciju podacima na steku: • esp i ebp. • Segmentni registri (16-bitni): • cs, ss, ds, es, fs i gs. • U flat modu, svi ukazuju na početak memorije. • Registri dostupni samo korišćenjem posebnih instrukcija • programski brojač eip, • statusna riječ procesora eflags.
Preslikavanje logičke u linearnu (flat) adresu • Logička adresa: (Selektor) + ofset • Selektor (16b) = segmentni registar • Ofset: adresa iz instrukcije(32bita) • Selektor pokazuje na deskriptor u okviru deskriptorske tabele (deo operativnog sistema) • Svi moderni OS podešavaju sadržaj deskriptora svih segmenata tako da pokazuju na logičku adresu 0, tako da je programeru dostupan ceo prostor od 4GB koristeći samo ofset i ne vodeći računa o segmentima tzv. Linearni adr. prostor • Po potrebi se može uključiti i straničenje, kada se logička adresa preslikava u fizičku adresu.
Opštenamjenski registri • Nižih 16 bita registara eax, ebx, ecx i edx se može koristiti i kao: • 16-bitni registar:ax, bx, cx i dx; • dva 8-bitna registra: • Npr. ax -> • ah – viši bajt, • al – niži bajt. • Imaju i posebne namene: • eax – akumulator, • ebx – bazni registar za adresiranje, • ecx – brojački registar, • edx – pomoćni registar za podatke u nekim instrukcijama, • esi i edi – indeksiranje pri adresiranju.
Registri za rad sa stekom • esp – pokazivač na vrh steka • pokazuje na zauzetu lokaciju na vrhu steka, • umanjuje se pre smeštanja podatka, • uvećava se posle skidanja podatka. • ebp – bazni registar za pristup argumentima potprograma i lokalnim promenljivim • Radi sa: • Rečima (16 bita – esp se menja za 2) • Duplim rečima (32 bita – esp se menja za 4)
Rad sa stekom • pushsrc ;stavlja na stek src • pop dst;sa steka upisuje u dst • pushfd;čuva eflags na steku • popfd;restaurira eflags sa steka ( ; u neprivilegovanom režimu ; bitovi posle OF neće se promeniti) • pushf/popf ; koristi samo donjih 16 bita eflags • pushad/popad ;čuvanje svih registara na steku: ; eax, ecx, edx, ebx, esp, ebp, ; esi, edi.
Statusna riječ procesora VM RF NT IOPL OF DF IF TF SF ZF AF PF CF • CF – prenos. • PF – parnost. • AF – pomoćni prenos za BCD aritmetiku. • ZF – rezultat nula. • SF – negativan rezultat. • TF – prekid posle svake instrukcije. • IF – maskiranje svih maskirajućih prekida. • DF – smjer za operacije nad stringovima. • OF – prekoračenje. • IOPL – I/O priviledge level • NT – nested task flag • RF – resume flag • VM – virtual 8086 mode
Načini adresiranja 1/2 • Neposredno: • mov eax, 10 • add ebx, 20h • Registarsko direktno (svi registri): • mov eax, 2 • mov edi, ebx • mov [ebp+6], ecx • Memorijsko direktno: • mov eax, suma • mov niz+6, edx ...
Načini adresiranja 2/2 • Registarsko indirektno (svi opšte namene): • mov [ebx], eax • Registarsko indirektno sa pomerajem: • mov [eax+88h], 2 • mov niz[edx], 2 • Bazno indeksno (adresa se sastoji od dva registra): • mov [ebx][edx], eax • Bazno indeksno sa pomjerajem (kao prethodno plus pomjeraj): • mov eax, niz[ebx][edi]
Skaliranje indeksa • Opšti oblik: • <konstanta>[<bazna_adresa>+<faktor>*<indeks>] • <faktor> može biti: • 1, • 2, • 4. • mov eax, suma[ebx+4*esi] • mov vrsta[edx+2*eax], bx
Napomene • Samo jedan operand u memoriji • postoji nekoliko izuzetaka. • Podrazumjevana upotreba segmentnih registara: • cs – kod, • ds – podaci, osim ako se u adresnom izrazu koristi ebp • ss – ako se u adresnom izrazu koristi ebp • Zamjena podrazumjevanogsegmentnog registra: • movax,ds:[ebp+4] • Flat režim = samo jedan segmentveličine 4GB.
Sistemski pozivi (Linux) • Tri načina: • direktno, • kroz prekid 0x80, • kod novijih procesora, instrukcijama SYSENTER i SYSEXIT, • indirektno, preko funkcija omotača iz standardne biblioteke. • int 0x80 • eax = 1: exit(int) • ebx: povratna vrijednost programa. • eax = 3: read(int, char*, int) • ebx: ručka fajla (0 za standardni ulaz), • ecx: adresa bafera, • edx: veličina bafera u B. • eax = 4: write(int, char*, int) • analogno prethodnom (1 je ručka za standardni izlaz).
Zdravo svete! (Linux, int) 3 • .intel_syntax noprefix.arch i386.data1poruka:.ascii “Zdravo svete!\n“kraj_poruke:.equ duzina_poruke, kraj_poruke – poruka.text1 • .globl _start_start:mov ebx, 1# mov ecx, offset porukalea ecx, porukamov edx, duzina_porukemov eax, 4int 0x80 2mov ebx,0mov eax,1int 0x80 2
Zdravo svete! (Linux, libc) 1 • .intel_syntaxnoprefix.arch i386.dataporuka:.asciz "Zdravosvete!\n”kraj_poruke:.equduzina_poruke, kraj_poruke – poruka.text .extern write.extern exit • .globl _start _start:push duzina_porukepush offset porukapush 1call write add esp, 12 #write(1,&poruka,# duzina_poruke); push 0call exit # exit(0);.end
Prevođenje, povezivanje i pokretanje • Asembliranje: • as -o p1.o p1.s • Povezivanje: • ld -o p1 -dynamic-linker /lib/ld-linux.so.2 p1.o -l c • l c: • uključuje biblioteku libc.a1, • važno: navesti biblioteku posle objektnih fajlova koji je koriste2. • dynamic-linker/lib/ld-linux.so.2 • uključuje biblioteku za dinamičko povezivanje. • Pokretanje • ./zdravo_svete
Potprogrami • Počinje labelom i opciono: • u redu ispred labele: .type <labela>, @Function • za potrebe umetanja informacija za debug: • na početku .func <naziv> [, <labela>]1 • na kraju .endfunc • Završava se instrukcijom za povratak iz potprograma: • ret [exp] # u flat modelu, bliski povratak (samo offset) • exp: broj koji po povratku treba dodati na esp • Poziv potprograma: • calldst • near poziv -> na steku se čuva EIP (u flat režimu se koristi ovaj pristup) • far poziv -> na steku se čuvaju CS i EIP • skače na dst
Proslijeđivanje parametara u registrima i globalnim promjenljivim • Prije poziva se upisuje u registar ili globalno dostupnu memorijsku lokaciju. • IZBEGAVATI, osim ako je primarna brzina. • U jednom trenutku smije postojati najviše jedan poziv takve funkcije -> 1 • Da li je dozvoljena rekurzija? • Pozivanje u prekidnim rutinama? • Pozivanje u konkurentnim nitima?
Proslijeđivanje parametara preko steka • Parametri se prije poziva ostavljaju na steku. • U funkciji im se pristupa pomoću registra EBP. • Zato svaka funkcija: • počinje sa:pushebpmovebp, espilienter 0, 01 • završava se sa:movesp, ebp ili leave2pop ebp • Ovako je obezbjeđeno da svaki poziv funkcije ima svoj zapis na steku (prikaz na sledećem slajdu).
Zapis poziva funkcije Bliski poziv Zapis tekućeg poziva neke funkcije Loc[m] -4*m ... enter 4*m,0 Loc[1] -4 EBPstaro retEIP +4 call naziv_funkcija Param[1] +8 Pred poziv funkcije: push param[n] … push param[1] ... Param[n] +4+4*n ESP EBP
Instrukcija enter • enter op1, op2: • op1: • broj bajtova koje je potrebno rezervisati za lokalne prom. • 16-bitna neposredna konstanta. • op2: • dubina ugniježđenosti funkcije (0-31), • govori koliko pokazivača na prethodne okvire treba iskopirati u tekući. • algoritam: 1 • pushebp • movebp, esp • Na stek doda pokazivače na okvirove prethodnih nivoa (stare vrednosostiepb registra) • subesp, op1
Konvencije pozivanja potprograma • Konvencija pozivanja potprograma definiše: • kako se poravnava stek, • kako se prosleđuju parametri, • ko radi oslobađanje prostora sa steka, • kako se vraća vrednost, • koji registri mogu da se koriste u funkciji bez da se čuvaju. • Konvencije koje se koriste u gcc-u: • cdecl (podrazumjevana) • stdcall • fastcall
cdecl konvencija pozivanja • Pred poziv funkcije, stek mora biti poravnat na granicu deljivu sa 16.1 • Argumenti se smeštaju na stek, s desna na levo. • Prostor na steku oslobađa pozivaoc: • izuzetak je skriveni pokazivač, kojeg oslobađa pozvana funkcija. • Vrednost se najčešće vraća u registru: • 1 bajt -> AL • 2 bajta -> AX • 4 bajta -> EAX (naredni primjer) • 8 bajtova -> EDX:EAX • struktura ili klasa -> preko skrivenog pokazivača 2 • Funkcija ne mora da čuva registre: eax, ecxiedx
Razlike stdcall i fastcall u odnosu na stdcall • stdcall • pozvani potprogram skida sve argumente sa steka • fastcall • prva dva argumenta, ako su celobrojnog tipa, prosleđuju se: • prvi u ecx • drugi u edx • ostali, kao i oni koji nisu celobrojnog tipa1 prosleđuju se preko steka • pozvani potprogram skida sve argumente sa steka • u slučaju da je promenljiv broj argumenata, na stek se stavljaju svi.
Napisati potprogram za sabiranje dva broja koristeći stdcall i cdecl konvencije 1 • Potprogram:stdcallsaberi:enter 0, 0moveax, [ebp+8]addeax, [ebp]+12leaveret 8 cdeclsaberi:enter 0, 0moveax, [ebp+8]addeax, [ebp]+12leaveret • Primjer poziva:push broj1push broj2call saberimov rezultat, eaxpush broj1push broj2call saberimov rezultat, eaxadd esp, 8
Napisati potprogram za sabiranje dva broja ? 58 EAX push 25 push 33 call saberi retAdr: mov rezultat, eax saberi: enter 0, 0 mov eax, [ebp+8] add eax, [ebp]+12 leave ret 8 EBP_old retAdr 33 33 25 25 ESP EBP
Vraćanje vrijednosti preko steka typedefstruct { int a, b; } struc; struc f(int x, int y){ struc a; a.a = x; a.b = y; return a;1 } void main(){ struc r = f(0x1122, 0x3344); } <f>: push ebp movebp, esp sub esp, 0x10 # za lokalne promjenljive moveax, 0xc[ebp] # eax = x mov [ebp-0x8], eax # a.a = eax moveax, [ebp+0x10] # eax + y mov[ebp-0x4], eax # b.b = eax movecx, [ebp+0x8] # ecx = &ret_bafer moveax, [ebp-0x8] # eax = a.a movedx, [ebp-0x4] # edx = a.b mov[ecx], eax # ret_bafer.a = eax mov[ecx+0x4], edx # ret_bafer.b = edx moveax, [ebp+0x8] # eax = &ret_bafer leave ret 0x4 # “oslobađa” skriveni parametar
Sabiranje i oduzimanje • adddst, src # dst=dst+src • adcdst, src # dst=dst+src+cf • subdst, src # dst=dst-src • sbbdst, src # dst=dst-src-cf • negdst # dst=-dst • incdst # dst=dst+1 • dec dst # dst=dst-1 • cmp src1, src2 # setujeflegove na osnovu # src1-src2
Množenje i dijeljenje • mul src # neoznaceno množenje • imul src # označeno množenje • src (8-bitni) množi sa al i rezultat ostavlja u ax • src (16-bitni) množi sa ax i rezultat ostavlja u dx:ax • src (32-bitni) množi sa eax i rezultat ostavlja u edx:eax • div src # neoznačeno dijeljenje • idiv src # označeno dijeljenje • Dijeli ax sa src (8-bitni) i rezultat ostavlja u al, a ostatak u ah. • Dijeli dx:ax sa src (16-bitni) i rezultat ostavlja u ax, a ostatak u dx • Dijeli edx:eax sa src (32-bitni) i rezultat ostavlja u eax, a ostatak u edx • Za množenje postoje i druge forme, sa dva i tri operanda
Proširivanje podataka znakom • cbw # proširuje ah sa znakom iz al • cwde # proširuje eax sa znakom iz ax • cwd # proširuje dx sa znakom iz ax • cdq # proširuje edx sa znakom iz eax
Logičke operacije • not dst # dst = ~dst • and dst, src # dst = dst & src • or dst, src # dst = dst | src • xor dst, src # dst = dst ^ src • test op1, op2 # setuje flegove na osnovu # op1 & op2
Pomjeranje i rotiranje • shldst, cnt # pomjeranje logički lijevo • saldst, cnt # pomjeranje aritmetički lijevo • shrdst, cnt # pomjeranje logički desno • sar dst, cnt # pomjeranje aritmetički desno • rordst, cnt # rotiranje desno • roldst, cnt # rotiranje lijevo • rcrdst, cnt # rotiranje kroz cf desno • rcldst, cnt # rotiranje kroz cf lijevo • cnt može biti: • 1, • neposredna vrijednost ili • registar cl.
Primjer • stanje prije: ax=0xf00f, CF=0, cl=2 • shlax, cl # 0xC03C, CF=1 (bit koji je ispao) • salax, cl # 0xC03C, CF=1 (bit koji je ispao) • shrax, cl # 0x3C03, CF=1 (bit koji je ispao) • salax, cl # 0xFC03, CF=1 (bit koji je ispao) • rorax, cl # 0xFC03, CF=1 (poslednji • rolax, cl # 0xC03F, CF=1 rotirani bit) • rcrax, cl # 0xBC03, CF=1 (poslednj • rclax, cl # 0xC03D, CF=1 izbačeni bit)
Uslovni skokovi 1/2 • Relativni skok. • Pomjeraj se posmatra kao označeni cijeli broj veličine: • 8 bita (short jump), ili • 16-bita (near jump), ili • 32-bita (near jump). • Test pojedinačnih flegova: • jz (je), (Jump if Zero; Jump if Equal) • jnz (jne), (Jump if Not Zero; Jump if Not Equal • js, (Jump if Sign set) • jns, • jp (jpe), (Jump if Parity flag set; Jump if Parity even) • jnp (jpo), (Jumo if No Parity flag set; Jump if Parity odd)
Uslovni skokovi 2/2 • Poređenje neoznačenih brojeva: • jb (jnae, jc) <(Jump Below; Jump Not Above or Equal) • jnb (jae, jnc) >= • jbe (jna) <= • jnbe (ja) > • Poređenje označenih brojeva: • jl (jnge) <(Jump Lower; Jump Not Greater or Equal) • jnl (jge) >= • jle (jng) <= • jnle (jg) >
if-then-else Izračunavanje uslova. • Viši programski jezici: • if (ecx<=0) {blok1 } else { blok2} • Blok1 i blok2 su nizovi instrukcija • Asembler: • cmp ecx,0jbe blok1jmp blok2blok1:…jmp daljeblok2:…dalje:… Ako je tačan, skače na blok1. U suprotnom na blok2.
Lokalne labele • Smanjuju mogućnost slučajnog ponavljanja iste labele. • Moguće koristiti 10 različitih: • <cifra>: • Sa svakog mjesta je moguće referisati prvu labelu: • unazad: • <cifra>b • odnosi se na prvo pojavljivanje labele “<cifra>:” prije tekuće instrukcije • unaprijed • <cifra>f • odnosi se na prvo pojavljivanje labele “<cifra>:” posle tekuće instrukcije
Primjer upotrebe lokalnih labela • #Primjer 1:cmp ecx,0je 1fjmp 2f1:…jmp 1f2:…1:… • #Primjer 2:1: add eax, ebx sub ebx, 1 test ebx, 1 je 2f dec ebx2: jnz 1b
Podrška za petlje 1/2 • Neke moguće implementacije: • Pomoću instrukcija uslovnog skoka • Pomogu namjenskih instrukcija za formiranje petlji • Pomoću potprograma i manipulacije povratnom adresom (strogo izbjegavati). • Instrukcije: • loop lab • loopz (loope) lab • loopnz (loopne) lab
Podrška za petlje 2/2 • Algoritam rada: • na početku instrukcije se prvo umanji ecx: ecx=ecx-1 • potom se provere uslovi izlaska iz petlje: • ecx==0, za loop • ecx==0 ili zf==0, za loope • ecx==0 ili zf==1, za loopne • Lab je labela početak petlje ili instrukcije skoka na početak petlje. • Lab mora biti u opsegu -128..+127B od adrese sledeće instrukcije. • jcxz lab ;skače na lab ako je ecx=0
Primjer, suma prvih N brojeva mov ecx, n #inicijalizacija #brojača jcxz 2f #ako je ecx = 0, preskače se #petlja mov eax, 0 #početna vrijednost #sume 1: add eax, ecx #računanje sume loop 1b #skok na početak #petlje ako je # ecx>0 2: ... #prva sledeća instrukcija
Bezuslovni skok • jmplab # skace na lab • Za lab se mogu koristiti modovi adresiranja kao i za podatke • Može se koristiti i indirektno memorijsko adresiranje. • Primeri: • jmpeax # skače se na adresu zapisanu u eax • jmp [eax] # skače se na adresu zapisanu na adresi iz eax • jmplab # skače se na labelulab • jmp [lab] # sa adrese lab se čita adresa skoka • jmp DWORD PTR lab # isto kao prethodno
Minimum dva broja 1 • Napisati program koji sa standardnog ulaza učitava dva broja i na standardni izlaz ispisuje manji od dva unijeta broja. • Traženje minimuma izdvojiti u funkciju u zasebnom fajlu (koristiti stdcall konvenciju pozivanja). • Zadatak uraditi: • tako da se oba fajla napišu na asembleru, • tako da se potprogram napiše na C-u, a program na asembleru, • tako da se potprogram napiše na asembleru, a da se program napiše na C-u.
Uvoženje i izvoženje simbola • Izvoženje: • Dvije sintakse: • .globl <naziv_simbola> • .global <naziv_simbola> • Ako je simbol definisan, ostaće vidljiv i za fazu povezivanja. • Ako simbol nije definisan, smatra se da se uvozi spolja. • Uvoženje: • .extern <naziv_simbola>