Instrukcije Prenosa, Aritmeticke Instrukcije i Nacini Adresiranja
-
Upload
acikamvulovic -
Category
Documents
-
view
340 -
download
11
description
Transcript of Instrukcije Prenosa, Aritmeticke Instrukcije i Nacini Adresiranja
-
1
5.
INSTRUKCIJE PRENOSA, ARITMETIKE INSTRUKCIJE I NAINI ADRESIRANJA
5.1 Instrukcije za prenos podataka
5.1.1 Uvod
U asembleru, programer mora biti svestan memorijskog prostora i pojedinosti raunara.
Kompajleri jezika visokog nivoa, kao to su C++ i Java vre striktnu proveru tipa promenljivih
i iskaza dodele. Asembleri pruaju veliku slobodu to se tie deklaracije i prenosa podataka, za
razliku od kompajlera, gde je to ogranieno. Asembleri ne vre preterano provere greki i imaju
veliki skup operatora i adresnih iskaza. Da bi se to iskoristilo na pravi nain, moraju se dobro
savladati svi detalji pre pisanja ozbiljnijih programa.
5.2 Tipovi operanada
Kao to je ranije navedeno, format x86 instrukcije je:
[labela:] mnemonik [operandi][ ; komentar ]
Usled toga to broj operanada moe biti razliit, instrukcije moemo podeliti na osnovu
broja operanada na bezadresne (nijedan operand), jednoadresne (jedan operand), dvoadresne
(dva operanda) i troadresne (tri operanda):
mnemonik
mnemonik [odredite]
mnemonik [odredite],[izvorite]
mnemonik [odredite],[izvorite-1],[izvorite-2]
Kako bi se dobila fleksibilnost u skup instrukcija, x86 asembler koristi razliite vrste
operanada. Sledei se najlake koriste:
Neposredni, koriste numerike izraze,
Registarski, koriste imena registara u procesoru,
Memorijski, referenciraju memorijsku lokaciju.
-
2
U tabeli 1 je prikazana jednostavna notacija za operande, preuzeta iz Intel-ovog
prirunika. Oni e se koristiti za opis sintakse pojedinanih instrukcija.
Tabela 1. Notacija instrukcijskih operanada
Operand Opis
Reg8 8-bitni registri opte namene: AH, AL, BH, BL, CH, CL, DH, DL
Reg16 16-bitni registri opte namene: AX, BX, CX, DX, SI, DI, SP, BP
Reg32 32-bitni registri opte namene: EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP
Reg Bilo koji registar opte namene
Sreg 16-bitni segmentni registri: CS, DS, SS, ES, FS,
GS
Imm 8-, 16- ili 32-bitna neposredna vrednost
Imm8 8-bitna neposredna vrednost veliine bajta
Imm16 16-bitna neposredna vrednost veliine rei
Imm32 32-bitna neposredna vrednost veliine dvostruke rei
Reg/mem8 8-bitni operand, koji moe biti 8-bitni registar opte namene ili memorijski bajt
Reg/mem16 16-bitni operand, koji moe biti 16-bitni registar opte namene ili memorijska re
Reg/mem32 32-bitni operand, koji moe biti 32-bitni registar opte namene ili memorijska dvostruka re
Mem 8-, 16- ili 32-bitni memorijski operand
5.3 Direktni memorijski operandi
Imena promenljivih su reference na ofsete unutar segmenta podataka. Na primer, sledea
deklaracija oznaava da je bajt koji sadri broj 10h alociran u segmentu podataka:
.data
var1 BYTE 10h
Programski kod sadri instrukcije koje dereferenciraju memorijske operande preko
njihovih adresa. Pretpostavimo da se var1 nalazi na ofsetu 10400h. Asemblerska instrukcija
koja e ga premestiti u registar AL je:
mov AL,var1
MASM e je asemblirati u sledeu mainsku instrukciju:
A0 00010400
Prvi bajt u mainskoj instrukciji je kod operacije. Ostatak je 32-bitna heksadecimalna
adresa promenljive var1. Iako je mogue da se piu programi koristei samo numerike adrese,
simbolike adrese kao to je var1 olakavaju referenciranje memorije.
-
3
Alternativna notacija
Neki programeri vie vole da koriste sledeu notaciju sa direktnim operandima, zato to
zagrade ukazuju na operaciju dereferenciranja:
mov al,[var1]
MASM omoguava i ovu notaciju.
5.3.1 Instrukcija MOV
Instrukcija MOV kopira podatak iz izvorinog operanda u odredini operand. Poznata je
kao instrukcija prenosa podataka. Njen osnovni format je da je prvi operand odredite, a drugi
izvorite:
MOV odredite, izvorite
Sadraj odredinog operanda se menja, a izvorini se ne menja. Transfer podataka sa
desna u levo je slino iskazu dodele u C++ ili Javi:
Odredite = izvorite;
MOV je veoma fleksibilna po pitanju operanada, ali se moraju potovati sledea pravila:
Oba operanda moraju biti iste veliine,
Oba operanda ne mogu biti memorijski operandi,
CS, EIP i IP ne mogu biti odredini operandi,
Neposredna vrednost se ne moe preneti u segmentni registar.
Sledi lista optih varijanti instrukcije MOV, iskljuujui segmentne regisre:
MOV reg,reg
MOV mem,reg
MOV reg,mem
MOV mem,imm
MOV reg,imm
Segmentni registri ne bi smeli direktno da se modifikuju u programu koji radi u
zatienom reimu. Sledee opcije su mogue kada se radi u realnom reimu, sa izuzetkom da
CS ne moe biti odredini operand:
MOV reg/mem16,sreg
MOV sreg,reg/mem16
Prenos iz memorije u memoriju
Jedna MOV instrukcija se ne moe koristiti za prenos podataka direktno iz jedne
memorijske lokacije u drugu. Umesto toga, morate preneti izvorini operand u registra pre nego
to se premesti u memoriju:
.data
var1 WORD ?
-
4
var2 WORD ?
.code
mov ax,var1
mov var2,ax
Mora se razmotriti najmanji broj bajtova koji je potreban celobrojnom izrazu kada se
kopira u promenljivu ili registar.
Preklapanje vrednosti
Sledei primer pokazuje kako se isti 32-bitni registar moe modifikovati koristei podatke
razliite veliine. Kada se oneWord premesti u AX, ona se prepisuje preko postojee vrednosti
AL. Kada se oneDword premesti u EAX, ona se prepisuje preko AX. Na kraju, kada se 0
premesti u AX, ona se prepisuje preko donje polovine EAX.
.data
oneByte BYTE 78h
oneWord WORD 1234h
oneDword DWORD 12345678h
.code
mov eax,0 ; EAX = 00000000h
mov al,oneByte ; EAX = 00000078h
mov ax,oneWord ; EAX = 00001234h
mov eax,oneDword ; EAX = 12345678h
mov ax,0 ; EAX = 12340000h
5.3.2 Proirivanje celih brojeva sa nulama ili znakom
Kopiranje manjih vrednosti u vee
Iako MOV ne moe direktno da kopira podatke iz manjeg operanda u vei, programeri
mogu to da zaobiu. Pretpostavimo da se count (neoznaeni, 16-bitni) mora premestiti u ECX
(32-bitni). Moe se postaviti ECX na nulu i preneti count u CX:
.data
count WORD 1
.code
mov ecx,0
mov cx,count
ta se deava ako pokuamo isti pristup sa oznaenim celim brojem jednakim -16?
.data
signedVal SWORD -16 ; FFF0h (-16)
.code
mov ecx,0
mov cx,signedVal ; ECX = 0000FFF0h (+65.520)
-
5
Vrednost u ECX (+65.520) je totalno razliita od -16. Sa druge strane, ako imamo
popunjen ECX sa FFFFFFFFh, a potom se kopira signedVal u CX, konana vrednost e biti
ispravna:
mov ecx,0FFFFFFFFh
mov cx,signedVal ; ECX = FFFFFFF0h (-16)
Efektivan rezultat ovog primera je bilo korienje bita najvee teine izvorinog operanda
(1) kako bi se popunilo gornjih 16 bitova odredinog operanda, ECX. Ova tehnika se naziva
proirivanje znakom. Naravno, ne moemo uvek pretpostaviti da je bit najvee teine 1. Na
sreu, Intel-ovi inenjeri su predvideli ovaj problem prilikom dizajna Intel386 procesora i
kreirali su MOVZX i MOVSX instrukcije.
5.3.3 Instrukcija MOVZX
Instrukcija MOVZX (move with zero-extend) kopira sadraj izvorinog operanda u
odredini operand i proiruje vrednost sa nulama do 16 ili 32 bita. Ova instrukcija se koristi
samo sa neoznaenim brojevima. Postoje tri varijante:
MOVZX reg32,reg/mem8
MOVZX reg32,reg/mem16
MOVZX reg16,reg/mem8
U svakoj od ove tri varijante, prvi operand (registar) je odredite, a drugi je izvorite.
Sledei primer proiruje sa nulama binarni broj 10001111 u AX registru:
.data
byteVal BYTE 10001111b
.code
movzx ax,byteVal ; AX = 0000000010001111b
Na slici 1 je prikazano kako se odredini operand proiruje sa nulama u 16-bitno
odredite.
Slika 1. Korienje MOVZX za kopiranje bajta u 16-bitno odredite
Sledei primeri koriste registre za sve operande, prikazujui sve varijacije u veliini:
mov bx,0A69Bh
movzx eax,bx ; EAX = 0000A69Bh
-
6
movzx edx,bl ; EDX = 0000009Bh
movzx cx,bl ; CX = 009Bh
Sledei primeri koriste memorijske operande za izvorite i daju isti rezultat:
.data
byte1 BYTE 9Bh
word1 WORD 0A69Bh
.code
movzx eax,word1 ; EAX = 0000A69Bh
movzx edx,byte1 ; EDX = 0000009Bh
movzx cx,byte1 ; CX = 009Bh
5.3.4 Instrukcija MOVSX
Instrukcija MOVSX (move with sign-extend) kopira sadraj izvorinog operanda u
odredini operand i proiruje ga sa znakom do vrednosti od 16 ili 32 bita. Ova instrukcija se
koristi samo sa oznaenim celim brojevima. Postoje tri varijante:
MOVSX reg32,reg/mem8
MOVSX reg32,reg/mem16
MOVSX reg16,reg/mem8
Operand se proiruje sa znakom tako to se uzima bit najvee teine manjeg operanda i
on se umnoava u odredinom operandu. Sledei primer proiruje sa znakom binarni broj
10001111b u AX:
.data
byteVal BYTE 10001111b
.code
movsx ax,byteVal ; AX = 1111111110001111b
Donjih 8 bitova se kopira, kao na slici 2. Bit najvee teine izvorite se kopira u svaki od
gornjih 8 bitova odredita.
Slika 2. Korienje MOVSX za kopiranje bajta u 16-bitno odredite
Heksadecimalna konstanta ima setovan bit najvee teine ako je njena heksadecimalna
cifra najvee teine vea od 7. U sledeem primeru, heksadecimalna vrednost koja se kopira u
BX je A69B, tako da vodea cifra A govori da je bit najvee teine setovan.
mov bx,0A69Bh
-
7
movsx eax,bx ; EAX = FFFFA69Bh
movsx edx,bl ; EDX = FFFFFF9Bh
movsx cx,bl ; CX = FF9Bh
5.3.5 Instrukcije LAHF i SAHF
Instrukcija LAHF (load status flags into AH) kopira donji bajt registra EFLAGS u AH.
Kopiraju se sledei flegovi: Sign, Zero, Auxiliary Carry, Parity i Carry. Koristei ovu
instrukciju, moe se lako sauvati kopija flegova u promenljivoj:
.data
saveflags BYTE ?
.code
lahf ; uitaj flegove iz AH
mov saveflags,ah ; sauvaj ih u promenljivoj
Instrukcija SAHF (store AH into status flags) kopira AH u donji bajt registra EFLAGS.
Na primer, moete dobiti ranije sauvane vrednosti iz promenljive:
mov ah,saveflags ; uitaj sauvanje flegove u AH
sahf ; kopiraj ih u Flags registar
5.3.6 Instrukcija XCHG
Instrukcija XCHG (exchange data) zamenjuje sadraj dva operanda. Postoje tri varijante:
XCHG reg,reg
XCHG reg,mem
XCHG mem,reg
Pravila za operatore u ovoj instrukciji su ista kao i za MOV, osim da XCHG ne prima
neposredne operande. U aplikacijama za sortiranje niza, XCHG prua jednostavan nain za
zamenu dva elementa u nizu. Sledi nekoliko primera korienja ove instrukcije:
xchg ax,bx ; razmena sadraja 16-bit registara
xchg ah,al ; razmena sadraja 8-bit registara
xchg var1,bx ; razmena 16-bit mem. operanda sa BX
xchg eax,ebx ; razmena sadraja 32-bit registara
Da bi se razmenila dva memorijska operanda, koristite registar kao privremeno skladite
i kombinujte MOV sa XCHG:
mov ax,val1
xchg ax,val2
mov val1,ax
5.4 Operandi sa direktnim ofsetom
Moete dodati pomeraj na ime promenljive, ime se kreira operand sa direktnim ofsetom.
Ovo vam omoguava pristup memorijskim lokacijama koje moda nemaju eksplicitne labele.
Ponimo sa nizom bajtova arrayB:
-
8
arrayB BYTE 10h,20h,30h,40h,50h
Ako koristimo MOV sa arrayB kao izvorinim operandom, automatski emo preneti prvi
bajt niza:
mov al,arrayB ; AL = 10h
Moemo pristupiti drugom bajtu u nizu dodavanjem 1 na ofset od arrayB:
mov al,[arrayB+1] ; AL = 20h
Treem bajtu se pristupa dodavanjem 2:
mov al,[arrayB+2] ; AL = 30h
Izraz kao to je arrayB+1 kreira tzv. efektivnu adresu, tako to dodaje konstantu na ofset
promenljive. Oznaavanje efektivne adrese sa zagradama ukazuje da se izraz dereferencira kako
bi se dobio sadraj memorije na datoj adresi. MASM ne zahteva zagrade, tako da su sledei
izrazi ekvivalentni:
mov al,[arrayB+1]
mov al,arrayB+1
5.4.1 Provera opsega
MASM nema ugraenu proveru opsega za efektivne adrese. Ako izvrimo sledei iskaz,
asembler e dohvatiti bajt memorije van niza. Rezultat je logika greka, tako da treba biti
posebno oprezan kada se radi referenciranje nizova:
mov al,[arrayB+20] ; AL = ??
5.4.2 Rei i dvostruke rei
U nizu 16-bitnih rei, ofset svakog elementa niza je dva bajta od prethodnog. Zbog toga
dodajemo 2 na arrayW u sledeem primeru kako bi se dohvatio drugi element:
.data
arrayW WORD 100h,200h,300h
.code
mov ax,arrayW ; AX = 100h
mov ax,[arrayW+2] ; AX = 200h
Na slian nain, drugi element niza dvostrukih rei je 4 bajta posle prvog:
.data
arrayD DWORD 10000h,20000h
.code
mov eax,arrayD ; EAX = 10000h
mov eax,[arrayD+4] ; EAX = 20000h
Primer. Sledei program demonstrira veinu primera koji su prikazani. Ne prikazuje nita na
ekranu, ali se moe koristiti debager.
TITLE Primeri prenosa podataka (Moves.asm)
-
9
INCLUDE Irvine32.inc
.data
val1 WORD 1000h
val2 WORD 2000h
arrayB BYTE 10h,20h,30h,40h,50h
arrayW WORD 100h,200h,300h
arrayD DWORD 10000h,20000h
.code
main PROC
; Demonstracija MOVZX instrukcije:
mov bx,0A69Bh
movzx eax,bx ; EAX = 0000A69Bh
movzx edx,bl ; EDX = 0000009Bh
movzx cx,bl ; CX = 009Bh
; Demonstracija MOVSX instrukcije:
mov bx,0A69Bh
movsx eax,bx ; EAX = FFFFA69Bh
movsx edx,bl ; EDX = FFFFFF9Bh
mov bl,7Bh
movsx cx,bl ; CX = 007Bh
; Razmena iz memorije u memoriju:
mov ax,val1 ; AX = 1000h
xchg ax,val2 ; AX=2000h, val2=1000h
mov val1,ax ; val1 = 2000h
; Adresiranje sa direktnim ofsetom (niz bajtova):
mov al,arrayB ; AL = 10h
mov al,[arrayB+1] ; AL = 20h
mov al,[arrayB+2] ; AL = 30h
; Adresiranje sa direktnim ofsetom (niz rei):
mov ax,arrayW ; AX = 100h
mov ax,[arrayW+2] ; AX = 200h
; Adresiranje sa direktnim ofsetom (niz dvostrukih rei):
mov eax,arrayD ; EAX = 10000h
mov eax,[arrayD+4] ; EAX = 20000h
mov eax,[arrayD+4] ; EAX = 20000h
exit
main ENDP
END main
-
10
5.5 Sabiranje i oduzimanje
5.5.1 Instrukcije INC i DEC
Instrukcije INC (increment) i DEC (decrement), dodaju 1 i oduzimaju 1 od operanda,
respektivno. Sintaksa je:
INC reg/mem
DEC reg/mem
Sledi nekoliko primera:
.data
myWord WORD 1000h
.code
inc myWord ; myWord = 1001h
mov bx,myWord
dec bx ; BX = 1000h
Na osnovu vrednosti odredinog operanda, menjaju se vrednosti flegova Overflow, Sign,
Zero, Auxiliary Carry i Parity. Ove instrukcije ne utiu na Carry fleg.
5.5.2 Instrukcija ADD
Instrukcija ADD dodaje izvorini operand na odredini operand iste veliine. Sintaksa je:
ADD dest,source
Vrednost u izvoritu se ne menja, a suma se smeta u odredini operand. Skup moguih
operanada je isti kao i za instrukciju MOV. Sledi kratak primer kojim se sabiraju dva 32-bitna
cela broja:
.data
var1 DWORD 10000h
var2 DWORD 20000h
.code
mov eax,var1 ; EAX = 10000h
add eax,var2 ; EAX = 30000h
Na osnovu vrednosti koja je smetena u odredini operand, menjaju se flegovi Carry,
Zero, Sign, Overflow, Auxiliary Carry i Parity.
5.5.3 Instrukcija SUB
Instrukcija SUB oduzima izvorini operand od odredinog operanda. Skup moguih
operanada je isti kao i za ADD i MOV. Sintaksa je:
SUB odredite,izvorite
Sledi kratak primer kojim se oduzimaju dva 32-bitna cela broja:
.data
var1 DWORD 30000h
-
11
var2 DWORD 10000h
.code
mov eax,var1 ; EAX = 30000h
sub eax,var2 ; EAX = 20000h
Interno, procesor moe da implementira oduzimanje kao kombinaciju negacije i
sabiranja. Na slici 3 je prikazano kako se izraz 4 1 moe napisati kao 4 + (-1). Za negativne
brojeve se koristi notacija u komplementu dvojke, tako da je -1 predstavljena kao 11111111.
Slika 3. Dodavanje vrednosti -1 na 4
Na osnovu vrednosti koja je smetena u odredini operand, menjaju se flegovi Carry,
Zero, Sign, Overflow, Auxiliary Carry i Parity.
5.5.4 Instrukcija NEG
Instrukcija NEG (negate) menja znak broja tako to ga konvertuje u komplement dvojke.
Sledei operandi su dozvoljeni:
NEG reg
NEG mem
Na osnovu vrednosti koja je smetena u odredini operand, menjaju se flegovi Carry,
Zero, Sign, Overflow, Auxiliary Carry i Parity.
5.5.5 Implementacija aritmetikih izraza
Na osnovu instrukcija ADD, SUB i NEG, moemo raunati izraze koji obuhvataju ove
tri instrukcije. Drugim reima, moe se simulirati ta C++ kompajler radi kada ita izraz kao
to je:
Rval = -Xval + (Yval - Zval);
Koristie se sledee oznaene 32-bitne promenljive:
Rval SDWORD ?
Xval SDWORD 26
Yval SDWORD 30
Zval SDWORD 40
-
12
Kada se izraz translira, posebno se rauna svaki deo i na kraju se oni kombinuju. Najpre,
vrimo negaciju kopije Xval:
; prvi izraz: -Xval
mov eax,Xval
neg eax ; EAX = -26
Potom se Yval kopira u registar, a Zval se oduzima:
; drugi izraz: (Yval - Zval)
mov ebx,Yval
sub ebx,Zval ; EBX = -10
Na kraju, dva dela (u EAX i EBX) se sabiraju:
; saberi izraze i zapamti:
add eax,ebx
mov Rval,eax ; -36
5.5.6 Flegovi na koje utiu sabiranje i oduzimanje
Kada se izvravaju aritmetike instrukcije, esto elimo da znamo kakav je rezultat. Da
li je negativan, pozitivan, ili jednak nuli? Da li je suvie veliki ili suvie mali da bi stao u
odredini operand? Odgovori na ova pitanja mogu nam pomoi da detektujemo greke u
raunanju. Koristiemo vrednosti procesorskih flegova kako bismo proverili rezultate
aritmetikih operacija. Takoe, koristimo i vrednosti statusnih flegova kako bismo aktivirali
instrukcije uslovnog grananja, osnovni alata programske logike. Sledi kratak pregled statusnih
flegova.
Fleg Carry ukazuje na prekoraenje u aritmetici sa neoznaenim celim brojevima.
Na primer, ako instrukcija ima 8-bitni odredini operand, ali generie rezultat vei
od 11111111b, setuje se Carry fleg.
Fleg Overflow ukazuje na prekoraenje u aritmetici sa oznaenim celim brojevima.
Na primer, ako instrukcija ima 16-bitni odredini operand, ali generie negativan
rezultat manji od -32.768d, setuje se fleg Overflow.
Fleg Zero ukazuje da je rezultat operacije jednak nuli. Na primer, ako je jedan
operand oduzet od drugog operanda iste vrednosti, setuje se fleg Zero.
Fleg Sign ukazuje da je rezultat operacije negativan. Ako je bit najvee teine
(MSB) odredinog operanda setovan (jednak 1), setuje se fleg Sign.
Fleg Parity ukazuje da li je paran broj jedinica u bajtu najmanje teine odredinog
operanda, odmah nakon to je aritmetika ili logika instrukcija izvrena.
Fleg Auxiliary Carry se setuje kada postoji prenos bita 1 sa pozicije 3 u bajtu
najmanje teine odredinog operanda.
-
13
5.6 Operacije sa neoznaenim vrednostima: Zero, Carry i Auxiliary Carry
Fleg Zero se setuje kada je rezultat aritmetike operacije jednak nuli. Sledei primeri
pokazuju stanje odredinog registra i Zero flega nakon izvravanja instrukcija SUB, INC i DEC:
mov ecx,1
sub ecx,1 ; ECX = 0, ZF = 1
mov eax,0FFFFFFFFh
inc eax ; EAX = 0, ZF = 1
inc eax ; EAX = 1, ZF = 0
dec eax ; EAX = 0, ZF = 1
5.6.1 Sabiranje i Carry fleg
Operacije sa flegom Carry se najlake objanjavaju ako posmatramo sabiranje i
oduzimanje odvojeno. Kada se sabiraju dva neoznaena cela broja, Carry fleg je kopija prenosa
iz bita najmanje teine odredinog operanda. Moe se rei da je CF = 1 kada zbir premauje
memorijski prostor odredinog operanda. U sledeem primeru, ADD setuje Carry fleg zato to
je suma (100h) suvie velika za AL:
mov al,0FFh
add al,1 ; AL = 00, CF = 1
Na slici 4 je pokazano ta se deava na nivou bitova kada se 1 sabira sa 0FFh. Prenos sa
bita najvee teine registra AL se kopira u Carry fleg.
Slika 4. Sabiranje 1 sa 0FFh setuje Carry fleg
Sa druge strane, ako se 1 sabira sa 00FFh u AX, suma lako staje u 16 bitova i Carry fleg
se ne setuje:
mov ax,00FFh
add ax,1 ; AX = 0100h, CF = 0
Ali sabiranje 1 sa FFFFh u AX registru daje prenos sa bita najvee teine u AX:
mov ax,0FFFFh
add ax,1 ; AX = 0000, CF = 1
-
14
5.6.2 Oduzimanje i Carry fleg
Operacija oduzimanja setuje Carry fleg kada se vei neoznaeni celi broj oduzima od
manjeg. Najlake je posmatrati efekat oduzimanja nad flegom Carry sa hardverske take
gledita. Pretpostavimo da procesor moe da vri negaciju nad pozitivnim celim brojem tako
to formira njegov komplement dvojke:
1. Izvorini operand se negira i sabira sa odredinim.
2. Prenos sa bita najvee teine se invertuje i kopira u fleg Carry.
Na slici 5 je prikazano ta se deava kada oduzimamo 2 od 1, koristei 8-bitne operande.
Najpre, vrimo negaciju dvojke i potom vrimo sabiranje. Suma (FFh) nije validna. Prenos sa
bita 7 se invertuje i smeta u Carry fleg, tako da je CF = 1. Sledi odgovarajui asemblerski kod:
mov al,1
sub al,2 ; AL = FFh, CF = 1
Instrukcije INC i DEC ne utiu na vrednost flega Carry. Primena instrukcije NEG nad
nenultim operandom uvek setuje Carry fleg.
Slika 5. Oduzimanje 2 od 1 setuje Carry fleg
5.6.3 Auxiliary Carry
Ovaj fleg (AC) ukazuje na prenos ili pozajmicu sa bita 3 u odredinom operandu.
Uglavnom se koristi u BCD aritmetici, ali se moe koristiti i za druge namene. Pretpostavimo
da sabiramo 1 sa 0Fh. Suma (10h) sadri 1 na poziciji bita 4 koja je preneta sa pozicije 3:
mov al,0Fh
add al,1 ; AC = 1
Sledi i artimetika:
0 0 0 0 1 1 1 1
+ 0 0 0 0 0 0 0 1
------------------
0 0 0 1 0 0 0 0
5.6.4 Parity
PF se setuje kada bajt najmanje teine odredinog operanda ima paran broj jedinica.
Sledee ADD i SUB instrukcije menjaju parnost AL:
-
15
mov al,10001100b
add al,00000010b ; AL = 10001110, PF = 1
sub al,10000000b ; AL = 00001110, PF = 0
Nakon ADD, AL sadri 10001110b (4 nule i 4 jedinice), tako da je PF = 1. Nakon SUB,
AL sadri neparan broj jedinica, tako da je PF = 0.
5.7 Operacije sa oznaenim brojevima: Sign i Overflow flegovi
5.7.1 Sign fleg
SF se setuje kada je rezultat aritmetike operacije sa oznaenim brojevima negativan. U
sledeem primeru se oduzima vei ceo broj (5) od manjeg (4):
mov eax,4
sub eax,5 ; EAX = -1, SF = 1
SF je kopija bita najvee teine odredinog operanda. Sledei primer pokazuje
heksadecimalne vrednosti registra BL kada se dobije negativan rezultat:
mov bl,1 ; BL = 01h
sub bl,2 ; BL = FFh (-1), SF = 1
5.7.2 Overflow fleg
OF se setuje kada rezultat aritmetike operacije sa oznaenim brojevima premauje ili
podbacuje odredini operand. Na primer, najvea pozitivna vrednost oznaenog bajta je +127,
a ako mu dodamo 1, dolazi do prekoraenja:
mov al,+127
add al,1 ; OF = 1
Na slian nain, najmanja negativna vrednost oznaenog bajta je -128. Oduzimanjem 1
od njega dovodi do podbaaja. Odredini operand ne sadri validan aritmetiki rezultat, tako da
je OF = 1:
mov al,-128
sub al,1 ; OF = 1
5.7.3 Test sabiranja
Postoji lak nain da se vidi da li je dolo do prekoraenja u aritmetici sa oznaenim
brojevima pri sabiranju dva operanda. Do prekoraenja dolazi kada:
Dva pozitivna operanda generiu negativan zbir,
Dva negativna operanda generiu pozitivan zbir.
Do prekoraenja nikad ne dolazi kada su znaci dva operanda pri sabiranju razliiti.
-
16
5.7.4 Kako se hardverski detektuje prekoraenje
Procesor koristi zanimljiv mehanizam za odreivanje stanja Overflow flega nakon
operacija sabiranja i oduzimanja. On vri operaciju iskljuivo ILI sa Carry flegom i bitom
najvee teine rezultata. Rezultat ove operacije se smeta u Overflow fleg.
Na slici 6, pokazano je kako sabiranjem 8-bitnog celog broja 10000000b i 11111110b
daje CF = 1, a MSB rezultata je 0. Drugim reima, 1 XOR 0 daje OF = 1.
Slika 6. Primer setovanja Overflow flega
5.7.5 Instrukcija NEG
Ova instrukcija daje nekorektan rezultat ako se odredini operand ne moe smesiti na
pravi nain. Na primer, ako premestimo -128 u AL i pokuamo sa negacijom, korektna vrednost
(+128) ne moe da stane u AL. Setuje se Overflow fleg, ukazujui da AL sadri nevalidnu
vrednost:
mov al,-128 ; AL = 10000000b
neg al ; AL = 10000000b, OF = 1
Sa druge strane, ako negiramo +127, rezultat je validan i OF = 0:
mov al,+127 ; AL = 01111111b
neg al ; AL = 10000001b, OF = 0
Kako procesor zna da li je aritmetika operacija sa oznaenim ili neoznaenim brojevima?
U stvari i ne zna. Procesor setuje sve statusne flegove nakon aritmetike operacije koristei
skup logikih pravila, bez obzira na to koji flegovi su relevantni. Programer odluuje koje
flegove treba posmatrati, a koje ignorisati, na osnovu njegovog znanja o vrsti operacije koja se
vri.
Primer. Sledei primer pokazuje raunanje razliitih aritmetikih izraza koristei ADD, SUB,
INC, DEC i NEG i pokazuje kako se odreeni flegovi ponaaju.
TITLE Sabiranje i oduzimanje (AddSub3.asm)
INCLUDE Irvine32.inc
.data
Rval SDWORD ?
Xval SDWORD 26
Yval SDWORD 30
Zval SDWORD 40
-
17
.code
main PROC
; INC i DEC
mov ax,1000h
inc ax ; 1001h
dec ax ; 1000h
; Izraz: Rval = -Xval + (Yval - Zval)
mov eax,Xval
neg eax ; -26
mov ebx,Yval
sub ebx,Zval ; -10
add eax,ebx
mov Rval,eax ; -36
; Primer sa Zero flegom:
mov cx,1
sub cx,1 ; ZF = 1
mov ax,0FFFFh
inc ax ; ZF = 1
; Primer sa Sign flegom:
mov cx,0
sub cx,1 ; SF = 1
mov ax,7FFFh
add ax,2 ; SF = 1
; Primer sa Carry flegom:
mov al,0FFh
add al,1 ; CF = 1, AL = 00
; Primer sa Overflow flegom:
mov al,+127
add al,1 ; OF = 1
mov al,-128
sub al,1 ; OF = 1
exit
main ENDP
END main
5.8 Operatori i direktive i veza sa operatorima
Operatori i direktive nisu izvrne instrukcije. Umesto toga, njih interpretira asembler.
Moete koristiti MASM direktive da biste dobili informacije o adresama i veliini podataka:
-
18
Operator OFFSET vraa udaljenost promenljive od poetka okruujueg segmenta.
Operator PTR omoguava redefinisanje podrazumevane veliine operanda.
Operator TYPE vraa veliinu (u bajtovima) operanda ili svakog elementa u nizu.
Operator LENGTHOF vraa broj elemenata u nizu.
Operator SIZEOF vraa broj bajtova koje koristi inicijalizator niza.
Dodatno, direktiva LABEL omoguava redefinisanje iste promenljive sa razliitom
veliinom atributa. Operatori i direktive ovde predstavljeni predstavljaju samo mali podskup
operatora koje podrava MASM. Takoe, MASM podrava i nasleene direktive, LENGTH
umesto LENGTHOF i SIZE umesto SIZEOF.
5.8.1 Operator OFFSET
Ovaj operator vraa ofset labele podatka. Ofset predstavlja udaljenost labele, u bajtovima,
od poetka segmenta podataka. Radi ilustracije, na slici 7 je prikazana promenljiva myByte
unutar segmenta podataka.
Slika 7. Promenljiva myByte
OFFSET primer
U sledeem primeru, deklarisaemo tri razliita tipa promenljivih:
.data
bVal BYTE ?
wVal WORD ?
dVal DWORD ?
dVal2 DWORD ?
Ako je bVal locirana na ofsetu 00404000h, operator OFFSET vraa sledee vrednosti:
mov esi,OFFSET bVal ; ESI = 00404000
mov esi,OFFSET wVal ; ESI = 00404001
mov esi,OFFSET dVal ; ESI = 00404003
mov esi,OFFSET dVal2 ; ESI = 00404007
OFFSET se moe primeniti i na operande sa direktnim ofsetom. Pretpostavimo da
myArray sadri pet 16-bitnih rei. Sledea MOV instrukcija dohvata ofset od myArray, dodaje
4 i premeta rezultujuu adresu u ESI. Moemo rei da ESI pokazuje na trei ceo broj u nizu:
.data
myArray WORD 1,2,3,4,5
.code
-
19
mov esi,OFFSET myArray + 4
Moete inicijalizovati promenljivu veliine dvostruke rei sa ofsetom druge promenljive,
ime se kreira pokaziva. U sledeem primeru, pArray ukazuje na poetak od bigArray:
.data
bigArray DWORD 500 DUP(?)
pArray DWORD bigArray
Sledei iskaz uitava vrednost pokazivaa u ESI, tako da registar moe da ukazuje na
poetak niza:
mov esi,pArray
5.8.2 Direktiva ALIGN
Direktiva ALIGN ravna promenljivu na granicu bajta, rei, dvostruke rei ili paragrafa.
Sintaksa je:
ALIGN bound
Granica moe biti 1, 2, 4 ili 16. Vrednost 1 ravna sledeu promenljivu na granicu od
jednog bajta (podrazumevano). Ako je granica 2, sledea promenljiva se ravna na parne adrese.
Ako je granica 4, sledea adresa je umnoak broja 4. Ako je granica 16, sledea adresa je
umnoak broja 16, granica paragrafa. Asembler moe da ubaci jedan ili vie praznih bajtova
pre promenljive kako bi popravio ravnanje. Zato treba voditi rauna o poravnanju? Zato to
procesor moe da obrauje podatke smetene na parnim adresama bre od onih na neparnim
adresama.
U sledeem primeru, bVal je proizvoljno locirana na ofsetu 00404000. Ubacivanjem
ALIGN 2 direktive pre wVal, dobija se ravnanje na parnom ofsetu:
bVal BYTE ? ; 00404000
ALIGN 2
wVal WORD ? ; 00404002
bVal2 BYTE ? ; 00404004
ALIGN 4
dVal DWORD ? ; 00404008
dVal2 DWORD ? ; 0040400C
Primetite da bi dVal bila na ofsetu 00404005, ali ALIGN 4 direktiva ju je pomerila na
ofset 00404008.
5.8.3 Operator PTR
Moete koristiti operator PTR kako biste redefinisali deklarisanu veliinu operanda. To
je neophodno kada pokuavate da pristupite promenljivoj koristei atribute veliine koji su
razliiti od onih koji se koriste za deklarisanje promenljive.
-
20
Pretpostavimo, na primer, da elite da premestite donji 16 bitova promenljive myDouble
veliine dvostruke rei u AX. Asembler nee dozvoliti sledei prenos zato to se veliine
operatora ne poklapaju:
.data
myDouble DWORD 12345678h
.code
mov ax,myDouble ; greka
Meutim, operator WORD PTR omoguava da se nia re (5678h) premesti u AX:
mov ax,WORD PTR myDouble
Zato nije 1234h premeteno u AX? Zato to x86 procesori koriste little endian format.
Na slici 8 prikazan je izgled myDouble promenljive na tri naina: najpre kao dvostruka re,
potom kao dve rei (5678h, 1234h) i na kraju kao etiri bajta (78h, 56h, 34h, 12h).
Slika 8. Izgled promenljive myDouble u memoriji
Procesor moe da pristupi memoriji na bilo koji od ova tri naina, nezavisno od naina
na koji je promenljiva definisana. Na primer, ako myDouble poinje na ofsetu 0000, 16-bitna
vrednost smetena na toj adresi je 5678h. Mogli bismo da dobijemo 1234h, re na lokaciji
myDouble + 2, koristei sledei iskaz:
mov ax,WORD PTR [myDouble+2] ; 1234h
Na slian nain, moemo koristiti operator BYTE PTR da premestimo jedan bajt iz
myDouble u BL:
mov bl,BYTE PTR myDouble ; 78h
Primetite da se PTR mora koristiti u kombinaciji sa jednim od standardnih asemblerskih
tipova podataka, BYTE, SBYTE, WORD, SWORD, DWORD, SDWORD, FWORD, QWORD
ili TBYTE.
Premetanje manjih vrednosti u vee
U sledeem primeru, prva re se kopira u donju polovinu EAX, a druga re se kopira u
gornju polovinu. Operator DWORD PTR ovo omoguava:
.data
wordList WORD 5678h,1234h
-
21
.code
mov eax,DWORD PTR wordList ; EAX = 12345678h
5.8.4 Operator TYPE
Ovaj operator vraa veliinu, u bajtovima, jednog elementa ili promenljive. Na primer,
TYPE od bajta je jednak 1, od rei je 2, od dvostruke rei je 4, a od etvorostruke rei je 8.
Slede primeri:
.data
var1 BYTE ?
var2 WORD ?
var3 DWORD ?
var4 QWORD ?
Sledea tabela pokazuje vrednosti svakog TYPE izraza.
Izraz Vrednost
TYPE var1 1
TYPE var2 2
TYPE var3 4
TYPE var4 8
5.8.5 Operator LENGTHOF
Ovaj operator prebrojava broj elemenata u nizu, definisanom sa vrednou koja se nalazi
na istoj liniji kao i njegova labela. Koristiemo sledee podatke kao primer:
.data
byte1 BYTE 10,20,30
array1 WORD 30 DUP(?),0,0
array2 WORD 5 DUP(3 DUP(?))
array3 DWORD 1,2,3,4
digitStr BYTE "12345678",0
Kada se ugnjedeni DUP operatori koriste u definiciji nizova, LENGTHOF vraa
proizvod dva brojaa. U sledeoj tabeli su prikazane vrednosti koje vraa LENGTHOF.
Izraz Vrednost
LENGTHOF byte1 3
LENGTHOF array1 30 + 2
LENGTHOF array2 5 * 3
LENGTHOF array3 4
LENGTHOF digitStr 9
Ako deklariete niz koji se prostire kroz vie programskih linija, LENGTHOF posmatra
samo podatke na prvoj liniji kao deo niza. Na osnovu sledeih podataka, LENGTHOF myArray
e dati vrednost 5:
myArray BYTE 10,20,30,40,50
BYTE 60,70,80,90,100
-
22
Sa druge strane, moete zavriti prvu liniju sa zarezom i nastaviti listu inicijalizatora na
sledeoj liniji. Na osnovu sledeih podataka, LENGTHOF myArray e dati vrednost 10:
myArray BYTE 10,20,30,40,50,
60,70,80,90,100
5.8.6 Operator SIZEOF
Ovaj operator vraa vrednost koja je ekvivalentna proizvodu LENGTHOF i TYPE. U
sledeem primeru, intArray ima TYPE = 2 i LENGTHOF = 32. Sledi, SIZEOF = 64:
.data
intArray WORD 32 DUP(0)
.code
mov eax,SIZEOF intArray ; EAX = 64
5.8.7 Direktiva LABEL
Ova direktiva omoguava umetanje labele i da joj dodelite atribut veliine bez alociranja
memorije. Svi standardni atributi veliine se mogu koristiti sa LABEL, kao to su BYTE,
WORD, DWORD, QWORD ili TBYTE. esta upotreba LABEL direktive je da omogui
alternativno ime i atribut veliine za promenljivu koja je sledea deklarisana u segmentu
podataka. U sledeem primeru, deklarisaemo labelu neposredno ispred val32 pod nazivom
val16 i daemo joj atribut WORD:
.data
val16 LABEL WORD
val32 DWORD 12345678h
.code
mov ax,val16 ; AX = 5678h
mov dx,[val16+2] ; DX = 1234h
Labela val16 postaje alijas za istu memorijsku lokaciju na kojoj je val32. Direktiva
LABEL ne alocira za samu sebe memorijski prostor.
Ponekad je potrebno da kreiramo vei ceo broj od dva manja. U sledeem primeru, 32-
bitna vrednost se uitava u EAX od dve 16-bitne promenljive:
.data
LongValue LABEL DWORD
val1 WORD 5678h
val2 WORD 1234h
.code
mov eax,LongValue ; EAX = 12345678h
5.9 Indirektno adresiranje
Direktno adresiranje nije praktino za obradu nizova zato to nije praktino koristiti
konstantne ofsete kako bi se adresiralo nekoliko elemenata niza. Umesto toga, koristimo
-
23
registar kao pokaziva (indirektno adresiranje) i manipuliemo sa vrednou u registru. Kada
operand koristi indirektno adresiranje, naziva se indirektni operand.
5.9.1 Indirektni operandi
U zatienom reimu, indirektni operand moe biti bilo koji od 32 registara opte namene
(EAX, EBX, ECX, EDX, ESI, EDI, EBP i ESP), u zagradi. Podrazumeva se da registar sadri
adresu nekog podatka. U sledeem primeru, ESI sadri ofset od byteVal. Instrukcija MOV
koristi indirektni operand kao izvorite, ofset u ESI se dereferencira, a bajt se premeta u AL:
.data
byteVal BYTE 10h
.code
mov esi,OFFSET byteVal
mov al,[esi] ; AL = 10h
Ako odredini operand koristi indirektno adresiranje, nova vrednost se smeta u memoriju
na lokaciju na koju ukazuje registar. U sledeem primeru, sadraj registra BL se kopira u
memorijsku lokaciju koju adresira registar ESI.
mov [esi],bl
5.9.2 General Protection Fault
U zatienom reimu, ako efektivna adresa ukazuje na oblast van segmenta podataka
programa, procesor izvrava general protection (GP) fault. Ovo se deava ak i kada instrukcija
ne modifikuje memoriju. Na primer, ako je ESI neinicijalizovan, sledea instrukcija e
verovatno generisati GP greku:
mov ax,[esi]
Registre treba uvek inicijalizovati pre nego to e se koristiti kao indirektni operandi. Isto
se odnosi i na programiranje u jezicima visokog nivoa sa pokazivaima. GP greke se ne
deavaju u reimu sa realnim adresama.
5.9.3 Korienje PTR sa indirektnim operandima
Veliina operanda moe da ne bude oigledna iz konteksta instrukcije. Sledea instrukcija
uzrokuje da asembler generie greku operand mora imati veliinu:
inc [esi] ; error: operand must have size
Asembler ne zna da li ESI ukazuje na bajt, re, dvostruku re ili neku drugu veliinu.
Operator PTR potvruje veliinu operanda:
inc BYTE PTR [esi]
-
24
5.9.4 Nizovi
Indirektni operandi su idealni za kretanje kroz niz. U sledeem primeru, arrayB sadri tri
bajta. Kako se ESI inkrementira, tako pokazuje na svaki bajt po redosledu:
.data
arrayB BYTE 10h,20h,30h
.code
mov esi,OFFSET arrayB
mov al,[esi] ; AL = 10h
inc esi
mov al,[esi] ; AL = 20h
inc esi
mov al,[esi] ; AL = 30h
Ako koristimo niz 16-bitnih celih brojeva, dodajemo 2 na ESI kako bismo adresirali svaki
naredni element niza:
.data
arrayW WORD 1000h,2000h,3000h
.code
mov esi,OFFSET arrayW
mov ax,[esi] ; AX = 1000h
add esi,2
mov ax,[esi] ; AX = 2000h
add esi,2
mov ax,[esi] ; AX = 3000h
Pretpostavimo da se arrayW nalazi na ofsetu 10200h. Na sledeoj slici je prikazana
poetna vrednost registra ESI u odnosu na veliinu podataka:
Primer: sabiranje 32-bitnih celih brojeva
Sledei deo koda sabira tri dvostruke rei. Pomeraj od 4 se mora dodati na ESI kako bi
pokazivao na sledei element u nizu jer su dvostruke rei duine 4 bajta:
.data
arrayD DWORD 10000h,20000h,30000h
.code
mov esi,OFFSET arrayD
mov eax,[esi] ; prvi broj
add esi,4
add eax,[esi] ; drugi broj
-
25
add esi,4
add eax,[esi] ; trei broj
Neka se arrayD nalazi na ofsetu 10200h. Tada sledea slika pokazuje poetnu vrednost
registra ESI u odnosu na veliinu podataka:
5.10 Indeksni operandi
Indeksni operand dodaje konstantu na vrednost u registru kako bi generisao efektivnu
adresu. Bilo koji od 32-bitnih registara opte namene se moe koristiti kao indeksni registar.
Postoje razliiti oblici obeleavanja koje dozvoljava MASM (zagrade su deo notacije):
konstanta[registar]
[konstanta + registar]
Prva notacija kombinuje ime promenljive sa registrom. Ime promenljive se prevodi u
konstantu koja predstavlja ofset promenljive. Sledi primer koji pokazuje obe notacije:
arrayB[esi] [arrayB + esi]
arrayD[edx] [arrayD + ebx]
Indeksni operandi su idealni za obradu nizova. Indeksni registar treba inicijalizovati na
nulu pre pristupanja prvom elementu niza:
.data
arrayB BYTE 10h,20h,30h
.code
mov esi,0
mov al,[arrayB + esi] ; AL = 10h
U poslednjem iskazu se sabira ESI sa ofsetom od arrayB. Adresa koja se generie izrazom
[arrayB + ESI] se dereferencira i bajt u memoriji se kopira u AL.
5.10.1 Dodavanje pomeraja
Drugi tip indeksnog adresiranja kombinuje registar sa konstantnim ofsetom. Indeksni
registar sadri osnovu adresu niza ili strukture, a konstanta identifikuje ofsete razliitih
elemenata niza. Sledei primer pokazuje kako se to radi sa nizom 16-bitnih rei:
.data
arrayW WORD 1000h,2000h,3000h
.code
mov esi,OFFSET arrayW
-
26
mov ax,[esi] ; AX = 1000h
mov ax,[esi+2] ; AX = 2000h
mov ax,[esi+4] ; AX = 3000h
5.10.2 Faktori skaliranja u indeksnim operandima
Indeksni operandi moraju da uzmu u obzir veliinu svakog elementa niza kada se raunaju
ofseti. Koristei niz dvostrukih rei, u sledeem primeru se mnoi indeks elementa u nizu (3)
sa 4 (veliina dvostruke rei) kako bi se generisao ofset elementa niza koji sadri 400h:
.data
arrayD DWORD 100h, 200h, 300h, 400h
.code
mov esi,3 * TYPE arrayD ; ofset od arrayD[3]
mov eax,arrayD[esi] ; EAX = 400h
Intel-ovi inenjeri su eleli da olakaju pisanje estih operacija, tako da su pruili nain
za raunanje ofseta, koristei faktor skaliranja. Faktor skaliranja je veliina elementa niza (re
= 2, dvostruka re = 4,). Prethodni primer emo prepraviti tako to emo postaviti u ESI
indeks elementa niza (3) i pomnoiti ESI sa faktorom skaliranja (4) za dvostruke rei:
.data
arrayD DWORD 1,2,3,4
.code
mov esi,3 ; indeks
mov eax,arrayD[esi*4] ; EAX = 4
Operator TYPE moe da olaka indeksiranje ako bi se arrayD redefinisao kao drugi tip u
budunosti:
mov esi,3 ; indeks
mov eax,arrayD[esi*TYPE arrayD] ; EAX = 4
5.10.3 Pokazivai
Promenljiva koja sadri adresu druge promenljive je pokaziva. Pokazivai su odlian
alat za manipulisanje nizovima i strukturama podataka, a omoguavaju i dinamiko alociranje
memorije. Programi za x86 arhitekturu koriste dva osnovna tipa pokazivaa, bliske (NEAR) i
daleke (FAR). Na njihove veliine utie trenutni reim rada procesora (16-bitni realni ili 32-
bitni zatieni), kao to je prikazano u tabeli 2.
Tabela 2. Vrste pokazivaa u 16-bitnom i 32-bitnom reimu
16-bitni reim 32-bitni reim
NEAR pokaziva 16-bitni ofset od poetka segmenta podataka
32-bitni ofset od poetka segmenta podataka
FAR pokaziva 32-bitna adresa segment-ofset
48-bitna adresa bira segmenta-ofset
-
27
U sledeem primeru se koriste NEAR pokazivai, tako da se smetaju u DWORD
promenljive. Pokaziva ptrB sadri ofset od arrayB, a ptrW ofset od arrayW:
arrayB BYTE 10h,20h,30h,40h
arrayW WORD 1000h,2000h,3000h
ptrB DWORD arrayB
ptrW DWORD arrayW
Opciono, moe se koristiti OFFSET operator kako bi se pojasnio odnos:
ptrB DWORD OFFSET arrayB
ptrW DWORD OFFSET arrayW
5.10.4 Upotreba TYPEDEF operatora
Ovaj operator omoguava kreiranje korisniki definisanih tipova koji svi imaju status
ugraenih tipova kada se deklarie promenljiva. TYPEDEF je idealan za kreiranje pokazivake
promenljive. Na primer, sledea deklaracija kreira novi tip podataka PBYTE koji je pokaziva
na bajt:
PBYTE TYPEDEF PTR BYTE
Ova deklaracija se obino smeta blizu poetka programa, pre segmenta podataka. Potom,
promenljive se mogu definisati korienjem PBYTE:
.data
arrayB BYTE 10h,20h,30h,40h
ptr1 PBYTE ? ; neinicijalizovano
ptr2 PBYTE arrayB ; ukazuje na niz
Primer. U sledeem primeru se koristi TYPEDEF kako bi se kreirala tri tipa pokazivaa
(PBYTE, PWORD, PDWORD). Kreira se nekoliko pokazivaa, dodeljuju im se ofseti nizova
i dereferenciraju se pokazivai.
TITLE Pokazivaci (Pointers.asm)
INCLUDE Irvine32.inc
; Kreiranje korisniki definisanih tipova.
PBYTE TYPEDEF PTR BYTE ; pokaziva na bajtove
PWORD TYPEDEF PTR WORD ; pokaziva na rei
PDWORD TYPEDEF PTR DWORD ; pokaziva na dvostruke rei
.data
arrayB BYTE 10h,20h,30h
arrayW WORD 1,2,3
arrayD DWORD 4,5,6
; Kreiranje pokazivakih promenljivih.
ptr1 PBYTE arrayB
ptr2 PWORD arrayW
-
28
ptr3 PDWORD arrayD
.code
main PROC
; Korienje pokazivaa za pristup podacima.
mov esi,ptr1
mov al,[esi] ; 10h
mov esi,ptr2
mov ax,[esi] ; 1
mov esi,ptr3
mov eax,[esi] ; 4
exit
main ENDP
END main
5.11 Instrukcije JMP i LOOP
Podrazumevano je da procesor uitava i izvrava programe sekvencijalno. Meutim,
naredna instrukcija moe biti uslovna, to znai da prosleuje kontrolu novoj lokaciji u
programu na osnovu vrednosti procesorskih statusnih flegova (Zero, Sign, Carry,).
Asemblerski programi koriste uslovne instrukcije za implementiranje iskaza programskih
jezika visokog nivoa, kao to su IF i ciklusi. Svaki od uslovnih iskaza ukljuuje mogue
prosleivanje kontrole (skok) na drugu memorijsku adresu. Prosleivanje kontrole ili grananje,
je nain kako se menja redosled po kojem se iskazi izvravaju. Postoje dve vrste prosleivanja
kontrole:
Bezuslovno prosleivanje. Kontrola se prosleuje novoj lokaciji u svakom sluaju.
Nova adresa se uitava u instrukcijski pokaziva, ime se nastavlja izvravanje sa
nove adrese. Ovo radi instrukcija JMP.
Uslovno prosleivanje. Deava se grananje ako je odreeni uslov ispunjen. Moe
se kombinovati veliki skup uslovnih instrukcija kako bi se kreirale uslovne logike
strukture. Procesor interpretira uslove kao true ili false na osnovu sadraja registra
ECX i flegova.
5.11.1 Instrukcija JMP
Ova instrukcija prouzrokuje bezuslovno prosleivanje kontrole odreditu, koje se
identifikuje preko labele koda koja se prevodi u ofset. Sintaksa je:
JMP odredite
-
29
Kada procesor izvri bezuslovno prosleivanje kontrole, ofset od odredita se premeta u
instrukcijski pokaziva, ime se izvravanje programa nastavlja sa nove lokacije.
Kreiranje petlje
Instrukcija JMP prua lak nain za kreiranje petlje time to se skae na labelu na poetku
petlje:
top:
.
.
jmp top ; repeat the endless loop
JMP je bezuslovni skok, tako da ovakva petlja e se beskonano izvravati ukoliko se ne
pronae nain za izlazak iz petlje.
5.11.2 Instrukcija LOOP
Instrukcija LOOP ponavlja izvravanje grupe iskaza odreeni broj puta. Registar ECX se
automatski koristi kao broja i dekrementira se svaki put kada se petlja ponovi. Sintaksa je:
LOOP odredite
Odredite mora biti u opsegu od -128 do +127 bajtova od trenutnog brojaa lokacije.
Izvravanje instrukcije LOOP ima dva koraka:
1. Oduzima se 1 od ECX.
2. ECX se poredi sa 0.
Ako ECX nije jednaka nuli, skae se na odredite. U suprotnom, ako je ECX jednako
nuli, ne dolazi do skoka, a kontrola se prosleuje instrukciji koja sledi posle petlje.
U sledeem primeru, dodajemo 1 na AX svaki put kada se petlja ponovo izvrava. Kada
se petlja zavri, AX = 5, a ECX = 0:
mov ax,0
mov ecx,5
L1:
inc ax
loop L1
esta programerska greka je da se ECX inicijalizuje na nulu pre poetka petlje. Ako se
to desi, LOOP instrukcija dekrementira ECX na FFFFFFFFh, a petlja se ponavlja
4.294.967.296 puta!
Sa druge strane, moete kreirati petlju koja je dovoljno velika da pree dozvoljeni opseg
relativnog skoka LOOP instrukcije. Sledi primer poruke o greci koju generie MASM zato to
je ciljna labela LOOP instrukcije bila suvie daleka:
error A2075: jump destination too far : by 14 byte(s)
-
30
Retki su sluajevi kada treba da eksplicitno modifikujete ECX unutar petlje. Ako to
uradite, LOOP instrukcija moe da ne radi kao to je oekivano. U sledeem primeru, ECX se
inkrementira unutar petlje. Nikad ne dostie nulu, tako da se petlja nikad ne zaustavlja:
top:
.
.
inc ecx
loop top
Ako ipak treba da modifikujete ECX unutar petlje, moete sauvati ECX u promenljivu
na poetku petlje, a restaurirati je neposredno pre LOOP instrukcije:
.data
count DWORD ?
.code
mov ecx,100 ; postavi broja petlje
top:
mov count,ecx ; sauvaj broja
.
mov ecx,20 ; promeni ECX
.
mov ecx,count ; vrati broja
loop top
5.11.3 Ugnjedene petlje
Kada se kreira petlja unutar druge petlje, mora se posebno voditi rauna o brojau
spoljanje petlje u ECX. Moete ga sauvati u promenljivoj:
.data
count DWORD ?
.code
mov ecx,100 ; postavi broja spoljanje petlje
L1:
mov count,ecx ; sauvaj broja spoljanje petlje
mov ecx,20 ; postavi broja unutranje petlje
L2:
.
.
loop L2 ; ponovi unutranju petlju
mov ecx,count ; vrati broja spoljanje petlje
loop L1 ; ponovi spoljanju petlju
Kao uopteno pravilo, ugnjedene petlje sa vie od dva nivoa su teke za pisanje. Ako
algoritmi koje koristite zahtevaju duboko ugnjedavanje petlji, premestite neke od unutranjih
petlji u subrutine.
-
31
Primer. Raunanje zbira elemenata niza.
U asembleru se radi u sledeim koracima:
1. Dodelite adresu niza registru koji e posluiti kao indeksni operand.
2. Inicijalizujte broja petlje na duinu niza.
3. Dodelite nulu registru koji uva zbir.
4. Kreirajte labelu kako biste oznaili poetak petlje.
5. U telu petlje, dodajte jedan element niza zbiru.
6. Ukaite na sledei element niza.
7. Koristite LOOP instrukciju da ponovite petlju.
Koraci 1 3 se mogu vriti u proizvoljnom redosledu. Sledi i programski kod.
TITLE Suma elemenata niza (SumArray.asm)
INCLUDE Irvine32.inc
.data
intarray DWORD 10000h,20000h,30000h,40000h
.code
main PROC
mov edi,OFFSET intarray ; 1: EDI = adresa od intarray
mov ecx,LENGTHOF intarray ; 2: inicijalizuj broja petlje
mov eax,0 ; 3: suma = 0
L1: ; 4: oznai poetak petlje
add eax,[edi] ; 5: saberi element
add edi,TYPE intarray ; 6: ukai na sledei element
loop L1 ; 7: ponovi dok ne bude ECX = 0
exit
main ENDP
END main
5.11.4 Kopiranje stringa
Programi esto kopiraju velike blokove podataka sa jedne lokacije na drugu. Podaci mogu
biti nizovi ili stringovi, ali mogu sadrati i druge tipove objekata. U asembleru, za ove operacije
se koristi petlja koja kopira string, predstavljen kao niz bajtova sa null znakom na kraju.
Indeksno adresiranje dobro radi za ove vrste operacija zato to isti indeksni registar referencira
oba stringa. Odredini string mora imati dovoljno prostora da primi kopirane karaktere,
ukljuujui null znak. Sledi i program.
-
32
TITLE Kopiranje stringa (CopyStr.asm)
INCLUDE Irvine32.inc
.data
source BYTE "Ovo je izvorni string",0
target BYTE SIZEOF source DUP(0)
.code
main PROC
mov esi,0 ; indeksni registar
mov ecx,SIZEOF source ; broja petlje
L1:
mov al,source[esi] ; uzmi karakter iz izvora
mov target[esi],al ; smesti ga u odredite
inc esi ; prei na sledei karakter
loop L1 ; ponovi za ceo string
exit
main ENDP
END main
Instrukcija MOV ne moe imati dva memorijska operanda, tako da se svaki karakter
premeta iz izvorinog stringa u AL, a potom iz AL u odredini string.