Instrukcije Prenosa, Aritmeticke Instrukcije i Nacini Adresiranja

32
1 5. INSTRUKCIJE PRENOSA, ARITMETIČKE INSTRUKCIJE I NAČINI ADRESIRANJA 5.1 Instrukcije za prenos podataka 5.1.1 Uvod U asembleru, programer mora biti svestan memorijskog prostora i pojedinosti računara. Kompajleri jezika visokog nivoa, kao što su C++ i Java vrše striktnu proveru tipa promenljivih i iskaza dodele. Asembleri pružaju veliku slobodu što se tiče deklaracije i prenosa podataka, za razliku od kompajlera, gde je to ograničeno. Asembleri ne vrše preterano provere greški i imaju veliki skup operatora i adresnih iskaza. Da bi se to iskoristilo na pravi način, 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 može biti različit, instrukcije možemo podeliti na osnovu broja operanada na bezadresne (nijedan operand), jednoadresne (jedan operand), dvoadresne (dva operanda) i troadresne (tri operanda): mnemonik mnemonik [odredište] mnemonik [odredište],[izvorište] mnemonik [odredište],[izvorište-1],[izvorište-2] Kako bi se dobila fleksibilnost u skup instrukcija, x86 asembler koristi različite vrste operanada. Sledeći se najlakše koriste: Neposredni, koriste numeričke izraze, Registarski, koriste imena registara u procesoru, Memorijski, referenciraju memorijsku lokaciju.

description

Instrukcije Prenosa, Aritmeticke Instrukcije i Nacini Adresiranja

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.