uvod u assemblersko programiranje u arm vd

Upload: ante-dilber

Post on 10-Mar-2016

245 views

Category:

Documents


11 download

DESCRIPTION

Skripta iz kolegija Arhitetektura racunala na temu uvod u asemblersko programiranje u embestu

TRANSCRIPT

  • Uvod u assemblersko programiranje s ARM 32-bitnom porodicom

    procesora

    1. Uvod

    Assemblerski jezici se koriste za programiranje raunala na razini koja je dovoljno

    blizu hardveru kako bi mogli dobiti znaajan uvid u stvarni hardver i njegove

    performanse.

    Kao informatiari, mi smo zainteresirani za razumijevanje asembler programiranja

    uglavnom zato to nam daje bolje razumijevanje naina na kojoj su implementriani

    vii programnski jezici kao C/C++, to se podrazumijeva kada govorimo o pozivu

    funkcije, for petlji ili pristupu nizu brojeva. Kako takve sloene strukture mogu biti

    izraene, kad imamo i dostupni su nam registri, memorija i jednostavne instrukcije

    sa tri operanda?

    Ba kao i na razina vii programskih jezika i asemblerski programi se kompajliraju

    na razinu strojnog koda. Ovaj proces se zove asembliranje, a softverski alat koji

    ovo izvodi se zove assembler.

    1.2 ARM arhitektura

    ARM arhitektura predstavlja relativno jednostavna implementaciju load / store

    arhitekture, odnosno arhitekture gdje se pristup glavnoj memoriji (RAM) obavlja

    preko Load i Store instrukcija, dok se sve raunske operacije provode na

    vrijednostima koje se dre u registrima.

  • Na primjer instrukcija, ADD R4, R1, R2 e pohraniti u registar R4 zbroj

    vrijednosti koje se uvaju u registrima R1 i R2.

    ARM arhitektura nudi 16 registara ope namjene, oznaenih od R0 do R15, od

    koji je posljednja tri imaju posebnu vanost..

    R13, takoer poznat kao SP, je stack pointer (pokaziva stoga) koji dri

    adresu gornjeg elementa na programskom stogu. Ona se automatski koristi

    u PUSH i POP instrukcijama za upravljanje pohrane i oporavak registara u stogu.

    R14, takoer poznat kao LR je link registar, i dri povratnu adresu, koja

    je adresa prve instrukcije koja se provodi nakon povratka iz trenutna funkcije.

    R15, takoer poznat kao PC je programsko brojilo, i uva adresu slijedee

    instrukcije koja se treba izvriti.

    O ovim registrima emo detaljnije kasnije u tekstu.

    2. Embest IDE i programiranje u assembleru

    U naim vjebama za razvojno okruenje koristiti emo Embest IDE. Napisati

    emo i analizirati jednostavni program zapisan preko Embest okruenja.

    C Kod Assembler

    int x=4;

    int y=7;

    z=x*y;

    _start:

    MOV r0, #0x4

    MOV r1, #0x7

    MUL r2, r1, r0

    stop:

    B stop

    .end

  • Nakon instalacije i nakon pokretanja EmbestIDE programa dobijamo slijedee

    korisniko suelje.

    Prvo emo kreirati novi radni prostor (workspace ) te novi projekt.

    (File->New Workspace)

    Otvori se dijaloki okvir gdje zadajemo lokaciju u datotenom sustavu i naziv

    projekta

  • Nakon to kliknemo u dijalokom okviru OK u

    programu e se pojaviti radni prostor i projekt sa

    nekoliko datoteka sa desne strane.

    Potom moramo ii na File-> New gdje dobijemo

    tekstualni okvir za upis naeg assemblerskog koda .

    Upiemo kod iz tablice.

    Nakon to upiemo tekst, spasimo sa File-> Save u

    direktorij sa naim projektom pod nazivom zad1.asm

  • Nakon toga potrebno je ubaciti nau spremljenu datoteku zad1.asm u projekt na

    nain prikazan na slici (desni klik mi na Project Source File)

    Sada kada imamo ubaenu asemblersku datoteku moramo konfigurirati nain i gdje

    e se izvesti sami kod ( File->Project->Settings)

    Otvori se dijaloki okvir u koje postavljamo slijedee stavke kao na slikama.

  • U ovom trenutku potrebno je spasiti promjene kliknuti OK, te na glavnom meniju

    ii na Build->Compile, te potom na Build-> Build Vjezba 1.

    Nakon to se uvjerimo da nema greaka pri kompajliranju i stvaranju zadatka

    (Build) potrebno je se opet vratiti na Project->Settings te u tabu Debug u kategoriji

    General pronai elf datoteku u debug direktoriju naeg projekta kao na slici te

    postaviti na Auto Download.

    U kategoriji Download takoer pronai elf datoteku postaviti adresu preuzimanja

    0x00008000 te oznaiti stavku Program Entry Point

  • Nakon svih predradnji ponovno kompajliramo i buildamo projekt te se spojima

    na plou sa ARM procesorom sa naredbom Debug->Remote Connect. Sada

    moemo izvoditi nae asemblerske programe.

  • 3. Assembler Jezik

    Kao to je prikazano u prvom primjeru, izjave u assembleru su strukturirane na

    slijedei nain:

    label: instruction

    Komentari se mogu umetnuti u C stilu (razgranieno s / * komentar* / ). Oznaka

    (label) je opcijska mogue je definirati instrukcije i bez oznake.

    Oznaka se koristi tako da uva adresu instrukcije u kodu - ovo je potrebno ako

    moramo napraviti grananje (branch) u kodu tzv. skok(jump) instrukcije. Za labele

    se mogu koristiti bilo koje alfanumerike sekvence. Mogu se koristiti ('_') kao i

    znak ('$') . Labele ne mogu zapoinjati sa brojevima.

    Instrukcije se mogu podijeliti u tri razliite skupine:

    Aritmetiki-Logike instrukcije izvode matematike operacije nad podacima:

    to moe biti aritmetika (zbroj, oduzimanje, mnoenje), logika (boolean

    operacije), ili relacijska (usporedba dvije vrijednosti) operacija.

    Branch instrukcije ili grananja mijenjaju tijek izvoenja programa,

    mijenjanjem vrijednosti programskog brojila (R15). One su potrebne za

    provedbu uvjetnih izjava, petlji i poziva funkcija.

    Load / Store instrukcije premjetaju podatke u i iz glavne memorije. Budui

    sve druge operacije rade samo s neposrednim konstantnim vrijednostima

    (kodirane u samoj instrukciji) ili s vrijednostima iz registara, load / store

    instrukcije su potrebne da se bave sa svim podacima (osim najmanjim

    skupovima podataka gdje koristimo naredbu MOV koja zaprima vrijednosti

    do 255)

  • U ostatku ovog odjeljka, mi emo predstaviti podskup ARM seta naredbi

    koji se mogu koristiti za pisanje cjelovitih programa. Ovaj podskup je mnogo manji

    nego cijeli skup Arm naredbi.

    3.1 Aritmetiko-Logike instrukcije

    Aritmetike instrukcije ukljuuju sljedee naziv instrukcije te registre nad kojim

    operiramo.

    Rd- odredini registar

    Rd- prvi registar sa podacima

    Rm drugi registar sa podacima

    #imm-umjesto drugog registra moemo korisiti 8 bitne neposredne

    vrijednosti (npr, #5)

    Sintaksa Semantika dodatno

    objasnjenje

    ADD Rd Rn RM / # IMM Rd = Rn + Rm / # IMM Zbrajanje

    SUB Rd Rn Rm / # IMM Rd = Rn - Rm / # IMM Oduzimanje

    MUL Rd Rn Rm Rd Rd = Rn* Rm / # IMM Mnoenje

    AND Rd Rn Rm/#imm Rd=Rn & Rm/#imm (bitwise and)

    EOR Rd Rn Rm/#imm Rd = Rn ^ Rm/#imm (bitwise exclusive

    or)

    ORR Rd Rn Rm/#imm Rd = Rn | Rm/#imm (bitwise or)

    MVN Rd Rm/#imm Rd = ~ Rm/#imm (bitwise negacija)

    CMP Rn Rm/#imm Status usporedba (, ==)

    MOV Rd Rm/#imm Rd = Rm/#imm

    Premjetanje iz

    jednog u drugi

    registar

  • Veina aritmetikih naredbi je poprilino jasna: sadraj registra Rd su zamjenjeni s

    rezultatima operacija koje se izvode na vrijednostima Rm ili Rn (odnosno

    konstantnom #imm).

    Na primjer, instrukcija SUB R3 R2 #12 smanjuje vrijednost registra R2 za 12.

    Potom se vrijednost registra R2 sprema u registar R3.

    Takoer, lako je prevesti C jezik u ARM instrukcije sve dok su sve promjenjive

    vrijednosti pohranjene u registrima. Razmotrimo slijedei fragment u C-u

    int i =0 , j =2 , k =4;

    i = k | j ; /* Bitwise or */

    Pod pretpostavkom da su vrijednosti tri varijable pohranjeni u registre

    R4, R5, i R6, tada se moe prevesti u fragment kako slijedi:

    MOV R4 #0 /* i =0; */

    MOV R5 #2 /* j =2; */

    MOV R6 #4 /* k =4; */

    ORR R4 R5 R6 /* i = k | j ; */

    Vano je napomenuti da je mnoenje tee implementirati u hardveru od drugih

    naredbi. Za razliku od veine drugih instrukcija, u MUL instrukciji registri Rd i

    Rm ne mogu biti u istom registru.

    Instrukcija usporedbe, CMP, ne sprema svoj rezultat u ope namjenski

    registar. Umjesto toga ona koristi posebni (ne izravno dostupan prema programeru)

    registar, koji se zove Processor Status Word. Rezultat usporedbe govori procesoru

    da li je vrijednost u Rn je vea, manja ili jednaka registru Rm (ili

    konstantnom operandu). Te se informacije mogu se koristiti da odluite hoete li

    obavljati uzastopne uvjetne instrukcije grananja ili ne.

  • 3.2 Branch Instrukcije

    Osnovna funkcionalnost Branch instrukcija je promijeniti vrijednost programskog

    brojila postavljanjem na novu vrijednost. Set instrukcija grananja ukljuuje

    sljedee:

    Sintaksa Semantika

    B label Skoi na label bezuvjetno

    BEQ label Skoi na label ako je prethodna usporedba jednaka

    BNE label Skoi na label ako je prethodna usporedba nije jednaka

    BGT label Skoi na label ako je prethodna usporedba Rn >Rm/#imm

    BGE label Skoi na label ako je prethodna usporedba Rn >=Rm/#imm

    BLT label Skoi na label ako je prethodna usporedba Rn

  • CMP R0 #0

    BGT label

    ADD R0 R0 #1

    Kljuna naredba je CMP koja mijenja stanje u registru CPSR.

    Najznaajniji bitovi u registru CPSR s krajnji N,Z,C iV.

    N - odreuje da li je broj negativan ili je manji od onog s kojim usporeujemo

    Z- odreuje da li je broj 0 odnosno da li su dva broja jednaka

    C Da li je dolo do preljeva, prenoenja ili posuivanja kod raunskih operacija

    V Preljev i prekoraenje kod brojeva sa predznakom

    Na osnovu stanja u CPSR registru naredba BGT moe izvriti uvjetno grananje.

    Prvo smo usporediti R0 sa 0, onda granamo na label ( ako i samo ako) je

    vrijednost sadrana u R0 vea od nule. S druge strane ako nije vea ide se na

    instrukciju 3.

    3.2 Prevoenje uvjetne naredbe

    Kljuno pitanje u razumijevanju assemblera je razumijevanje kako naredbe za

    uvjetno izvoenje koda iz viih jezika mogu biti implementirani u asemblerskom

    jeziku niskog nivoa. Prvi korak je nauiti kako predstaviti u assembler if the-

    else konstrukt iz C-a.

  • Pretpostavimo da su x i y sauvani u R4 i R5, moemo prevesti C fragment na

    slijedei nain:

    C Kod Assembler

    int x , y ;

    ...

    if(x >0) {

    y =1;

    } else {

    y =2;

    }

    return y ;

    .equ x, 1

    _start:

    MOV r4, #x

    CMP r4, #x

    BLE else

    MOV r5, #1

    end:

    B end

    else:

    MOV R5,#2

    B end

    Moemo vidjeti da u liniji 3 i 4 u assembleru postavljamo uvjetno grananje koje

    doputa da preskoimo then dio koda (y=1; u naem primjeru) ako se uvjet (x>0)

    ne izvri. S druge strane koristi se i provodi then dio. U kasnijem sluaju

    moramo osigurati da se else ne izvrava u originalnom C konstruktu , dva dijela

    su uzajmno iskljuiva : samo se jedna izvrava kada se uvjet ispunjava. Na taj

    nain u liniji 8 dodajemo bezuvjetno grananje B kako bi preskoili else dio i

    pomakli se direktno na kraj preko labele end.

    C kod Assembler

    int res;

    int x=0;

    int mx=4

    int mn =7

    .equ x, 0

    .equ mx, 4

    .equ mn, 7

    _start:

    .Lt_mx:

    cmp r0,r1

    bge stop

    add r3,r0,r2

  • if(x>=mx)

    res=mn+x-mx;

    else if(x0)

    {

    y*=x;

    x--;

    }

    .equ x, 5

    .equ y, 1

    _start:

    MOV r5, #y

    MOV r4, #x

    loop:

    CMP r4, #0

    BLE end

    MUL r6, r5, r4

    MOV r5, r6

    SUB r4, r4, #1

    B loop

    end:

    MOV r0, r5

    stop:

    B stop

  • Moemo vidjeti u liniji 6 i 7 u asemblerskom kodu da postavljamo i izvravamo

    uvjetno grananje koje doputa da izaemo iz petlje kada uvjet u izvornom kodu

    (x>0) nije osiguran.. Nakon kraja tijela petlje moramo vratiti se i provjeriti uvjet

    kako bi zapoeli sa iteracijom petlji. U liniji 12 dodajemo bezuvjetno grananje B

    kako bi se vratili na poetak petlje oznaene sa oznakom labelom loop.

    Sa do-while petljom moemo izvesti slian prijevod. Ovdje je C fragment koji

    rauna istu funkciju faktorijel osim to je x==0, povratna vrijednost je 0 radije nego

    1.

    C Kod Assembler

    int x , y ;

    x=5;y =1;

    do {

    y *= x ;

    x - -;

    } while (x >0) ;

    return y ;

    .equ x, 5

    .equ y, 1

    _start:

    MOV r5, #y

    MOV r4, #x

    loop:

    MUL r6, r5, r4

    MOV r5, r6

    SUB r4, r4, #1

    CMP r4, #0

    BGT loop

    MOV r0, r5

    stop:

    B stop

    Jedina uoljiva razlika je u odnosu na while verziju u tome to sada se granamo na

    poetak koji je uvjetan i trebamo samo jednu granu budui nemamo kontrole

    provjere x>0 na poetku.

    Moe se initi da prevoenje for petlje predstavljaju je tee budui je kosntrukcija

    petlje kompleksnija. Ipak, nije tako budui se for petja se moe odmah prevesti u C

    while petlju. Naprimjer razmotrimo slijedei fragment C koda:

  • int x , y ;

    ...

    for ( y =1; x >0; x - -) y *= x ;

    return y ;

    Lako je vidjeti da petlja u liniji 3 ima isto ponaanje kao while petlja. Generalno , C

    for petlja ima slijedeu strukturu:

    for(inicijalizacija; uvjet; korak petlje) tijelo petlje.

    Petlju for lako moemo prevesti u while petlju na slijedei nain:

    Inicijalizacija

    while(uvjet)

    {

    Tijelo-petlje

    Korak_petlje

    }

    3.3 Load / Store Instrukcije

    Posljednje, ali ne i najmanje vano, load i store instrukcije obavljaju prijenos

    podataka iz memorije prema registrima i obrnuto.

    Sljedee instrukcije omoguuju nam rad s podacima veliine rije (32 bita) i

    veliine byte (8 bita)

    Sintaksa Semantika

    LDR Rd [Rn, Rm/#imm] Rd = mem[Rn+Rm/#imm] (32 bit copy)

    STR Rd [Rn, Rm/#imm] mem[Rn+Rm/#imm] = Rd (32 bit copy)

    LDRB Rd [Rn, Rm/#imm] Rd = mem[Rn+Rm/#imm] (8 bit copy)

  • STRB Rd [Rn, Rm/#imm] mem[Rn+Rm/#imm] = Rd (8 bit copy)

    PUSH { register list } Push registers onto stack

    POP { register list } Pop registers from stack

    Load instrukcijama vrijednosti se itaju iz odreene memorijske adrese i uitavaju

    u registar Rd, dok su store instrukcije Rd izvori iz kojih se podaci itaju ,a

    vrijednosti spremaju u memoriji. Memorijska adresa se u oba sluaja rauna kao

    suma baze Rn i odmaka (Rm ili kosntante). Uobiajeno programer koristi ove

    naine da pristupe poljima podataka. Razmotrimo slijedei C kod:

    1. char AA [10] , BB [10];

    2. ...

    3. AB [ i ]= BB [ i ];

    Gdje su AA i BB polja. Ako se baza adrese AA i BB uvaju u R4 i R5, a indeks i

    se uva u R1, tada se liniji 3 moe prevest kao

    LDRB R6 R5 R1

    STRB R6 R4 R1

    Budui je memorija adresirana po byte-ovima (svaka adresa odgovara specifinom

    byte-u) kada se pristupa polju integera moramo modificirati indeks polja kako bi

    inkrementirali po koraku 4 umjesto po koraku 1 jer integer zauzima 4 byte-a.

    int AA [10] , BB [10];

    ...

    3 i =2;

    4 AA [ i ]= AB [ i ];

  • Odgovarajui ARM prijevod koristi istu pohranu za adrese i varijable

    MOV R1 #8 /* 2*4: addressing in bytes ! */

    LDR R6 R5 R1

    STR R6 R4 R1

    LDR se koristit kada se sluimo rijeima (32 bita) dok LDRB kada imamo byte-

    ove(8 bita). Slino je i za STR.

    Push i Pop instrukcije se koristi da upravljaju programskim stogom koje se

    kolekcija zapisa za sve funkcije aktivne u isto vrijeme kao rezultat ugnijeenih

    poziva funkcija.

    Globalna podatkovna sekcija

    Svaki program vidi memorijski prostor koji je rezerviran za njega. Memorijski

    prostor se moe koristiti za uvanje podataka: npr, moemo uvati globalne

    skalarne varijable, stringove , polja ili matrice.

    Kako bi rezervirali prostor namijenjen globalnoj podatkovnoj memoriji moramo

    dati dovoljno informacija o veliini prostora potrebnog za memoriju kao i

    inicijalizacijske vrijednosti. Direktive .int, .byte, .float, .string respektivno

    rezerviraju memoriju za 32-bitni integer, 8-bitni integer 32- bitni floating point broj

    i zero terminated string (veliina stringa je jedan byte po znaku plus jedan dodatna

    znak za kraj stringa)

    Ovim podacima moemo pristupiti sa load i store instrukcijama

    Zadatak 7. Pronaimo najvei zajedniki djelitelj izmeu dva zadana broja preko

    niza brojeva

  • C kod Assembler

    while(a!=b)

    { if(a>b)

    a=a-b;

    else

    b=b-a;

    }

    arr:

    .byte 100,64

    eoa:

    .align

    _start:

    ldr r3, =arr

    ldr r4, =eoa

    ldrb r0, [r3], #1

    ldrb r1, [r3 ], #1

    gcd:

    cmp r0, r1

    beq stop

    blt less

    sub r0, r0, r1

    bal gcd

    less:

    sub r1, r1, r0

    bal gcd

    stop:

    B stop

    U sluaju da koristimo .byte ili polu rijei tip podataka moramo koristiti direktiva

    .align . Budui instrukcije zauzimaju 4 byte-a, adresa prvog byte mora biti djeljiva

    sa 4 pa stoga umeemo dodatne byte-ove kako bi slijedea adresa instrukcije bila

    viekratnik broja 4.

    Zadatak 8. Zbrojite elemente niza

    C kod Assembler

    char arr[]={10,20,25}

    int sum=0;

    int i=0;

    do

    {

    sum=sum+char[i];

    i++;

    }while(i

  • cmp r1, r0

    Zadatka 9. Napiite program u assembleru kojim ete pronai duljinu niza znakova.

    str: .asciz "Hello World

    .equ nul, 0

    .align

    start:

    ldr r0, =str

    mov r1, #0

    loop:

    ldrb r2, [r0], #1

    add r1, r1, #1

    cmp r2, #nul

    bne loop

    sub r1, r1, #1

    stop: b stop

    Direktiva .asciz prihvata string znakove kao argument. String znakovi se smjetaju

    u susjedne i kompaktne memorijske lokacije.

    Stog

    Stog je podatkovna struktura (nain na koji organziramo podatke). Stog se sastoji

    od tri tipine operacije: pristup vrhu stoga, postavljanje na vrh (push), skidanje sa

    vrha (pop). U ovisnosti o kontesktu moemo samo imati pristup vrhu stoga. Kada

    govorimo o funkcijama to je dio memorije koju posjeduje funkcija, a koji se

    dinamiki aktivira kada se pozove funkcija. Za kontrolu stoga sluimo se

    pokazivaem stoga (stack pointer) odnosno registrom sp. U registru se samo nalazi

    pohranjen vrh stoga. Podruje memorije koje se stvara kada se pozove funkcija

    nazivamo lokalnom memorijom funkcije i sastoji se od poetne vrijednost sp a

  • kada je funkcija pozvana i trenutne vrijednost pokazivaa stoga (sp-a). Podruje se

    se poveava kada dodajemo elemente, a smanjujemo kada skidamo elemente sa

    stoga. Stavke se skidaju obrnutima redoslijedom u kojem su dodavane (LIFO).

    .equ x, 45

    .equ y, 64

    .equ stack_top, 0x1000

    .global _start

    .text

    _start:

    MOV sp, #stack_top

    MOV r0, #x

    STR r0, [sp]

    MOV r0, #y

    LDR r1, [sp]

    ADD r0, r0, r1

    STR r0, [sp]

    stop:

    B stop

    .end

    /* definiramo varijablu x i dodajmo 45 */

    /* definiramo varijablu y i dodajmo 64 */

    /* definiramo vrh stoga 0x1000*/

    /* simbol poetka programa */

    /* dodaj vrijednost x u registar R0 */

    /* spasi vrijednost R0 na stog*/

    /* dodaj vrijednost y na R0 */

    /* preuzmi vrijednost iz stoga na R1 */

    /* program zavrava i ulazi u beskonanu

    petlju*/

  • .equ stack_top, 0x1000

    .global _start

    .text

    _start:

    MOV sp, #stack_top

    adr r4, pod

    LDR r0,[r4],#4

    LDR r1,[r4],#4

    ADD r2,r0,r1

    LDR r0,[r4],#4

    MUL r3,r2,r0

    STR r3,[r4]

    STR r3,[sp]

    stop:

    B stop

    pod:

    .word 0x000f, 0x00ff, 0x0fff, 0xffff

    .end

    /*stavi na vrh stoga 0x1000*/

    /*ulazna toka*/

    /* postavlja se stack pointer na vrh stoga */

    /* stavlja se u r4 adresa podataka */

    /* u r0 prvi podatak iz memorije 0x000F */

    /* u r1 drugi podatak iz memorije 0x00FF */

    /*zaustavljanje grananja*/