Viikkoharjoitus 4

Jatkamme edellisen viikon linjoillai eli x86-assemblyllä. Nouda alla oleva koodirunko tästä.

;TIEA325
;Jani Kurhinen
;9.4.2008
;fibocalc.asm
;
;Valmiin koodin on tarkoitus vastata seuraavanlaista C-kielistä koodia
;
;int fibonacci(int i)
;{       
;       if (i==1 || i==2)
;         return 1
;       return finonacci(i-1) + fibonacci(i-2);
;}
;
;
;Käännä jalavassa komennolla
;nasm -f elf calcfibo.asm
;Lisäksi tarvitset myös pääohjelman, joka kutsuu tätä modulia.
;Linkitys gcc:n avustuksella esim.
;gcc -m32 -o calc calcfibo.o mainmodule.o
;
;ebp on ohjelmalohkon pinomuistialueen alkuosoitin
;esp on pino-osoitin
;*push ja pop-käskyt muokkaavat esp:tä, mutta sitä voi myös itse käpistellä
;*HUOM! x86:ssa pino kasvaa "alaspäin"
;eax on akkurekisteri, johon aritmeettiset operaatiot tallentavat tuloksensa.
;Myös aliohjelmat palauttavat arvonsa akussa.
;
;Yleiskäyttöisiä rekistereitä käytettäessä on syytä huomioida, että
;aliohjelmilla on lupa muuttaa rekistereiden EAX,ECX ja EDX sisältöä. Sen
;sijaan rekistereiden EBX, EDI sekä ESI arvojen voidaan olettaa säilyvät
;aliohjelmakutsun yli!
;
;
;Koodirunko palauttaa pinossa välitetyn parametrin mukaisen fibonaccin 
;luvun, ja siinä on valmis toteutus 1. ja 2. luvulle.
;
;Alla tarvittavia komentoja
;
;cmp	vertaa			Esim. cmp eax,1
;je	hyppää, jos samat	Esim. je R1
;jmp	pakotettu hyppy 	Esim. jmp R1
;sub	Vähennyslasku		Esim. sub eax,2
;dec	Vähennä yhdellä		Esim. dec eax
;add	Yhteenlasku		Esim. add esp,4
;mov	Siirrä sisältö		Esim. mov ebx,eax
;	Siirrä osoittesta	Esim. mov eax,[ebp+12]
;push	Lisää pinoon		Esim. push eax
;pop	Poista pinosta		Esim. pop ebx
;call	Aliohjelmakutsu		Esim. call fibonacci
;ret	Aliohjelmasta paluu	Esim. ret
;
;Keosta varattavat muistilohkot. Kukin label on osoite.
        SECTION .data

;Varsinainen koodi tulee tähän.
        SECTION .text

R1:			;Hyppyviite eli label
        mov     eax,1	;Akkuun arvo 1
RETURN:			;Hyppyviite eli label
        mov     esp,ebp ;Palautetaan pino-osoitin,
        pop     ebx     ;EBX, sekä
        pop     ebp     ;kantaosoitin alkuperäisiin arvoihin
        ret

        global fibonacci        ;komponentin entrypointti.
fibonacci:                      ;Hyppyviite eli label

        push    ebp     ;Vanha basepointteri talteen pinoon
        push    ebx     ;BX:n arvo talteen
        mov     ebp,esp ;basepoitterille uusi arvo nykyisen pinon päältä
        sub     esp,8   ;Varataan tilaa kahdelle dword-muuttujalle (integer)


        mov     eax, [ebp+12]   ;parametri akkuun
        cmp     eax,1           ;verrataan akussa olevaa tulosta lukuun 1
        je      R1              ;Hypätään, jos sama.
        mov     eax, [ebp+12]   ;parametri akkuun
        cmp     eax,2           ;verrataan akussa olevaa tulosta lukuun 2
        je      R1              ;Hypätään, jos sama.
	;
        ;Jos tänne päädytää, on parametri siis suurempi kuin 2
	;Täydennä siten, että koodi kutsuu rekursiivisesti
	;itseään. 
	;
	jmp RETURN              ;ehdoton hyppy poistumisrutiiniin


Alla olevaa koodi kutsuu fibocalc:ia arvolla 6

        extern printf;Myös assemblerissa voidaan käyttää ulkoisia funtioita.
                     ;Tämä vastaa C-kielen funktion esittelyä.
        extern fibonacci

        SECTION .data
print_string:   db "Tulos on %d",10,0 ;Merkkijono, rivinvaihto ja loppunolla.

        SECTION .text
        global main
main:                   ;Tässä on main-label, ei siis tuo ylempi direktiivi.
        push    ebp     ;Vanha basepointteri talteen pinoon
        mov     ebp,esp ;basepoitterille uusi arvo nykyisen pinon päältä
        sub     esp,8	;Varataan tilaa parille dwordille

        mov     eax,6	;Vakio 6 akkuun
        push    eax	;Parametri pinoon
        call fibonacci
        add     esp,4	;Parametrin poisto pinosta
        mov     [ebp-4],eax;Tallennetaan tulos paikalliseen muuttujaan.

        ;TULOSTUS#################
        push    dword [ebp-4]   ;Parametrit pinoon aliohjelmakutsua varten.
        push    dword print_string
        call printf
        add     esp,8;  ;Parametrien poisto pinosta aliohjelman jälkeen
        ;END###############


        mov     esp,ebp ;Palautetaan stackpoitteri ja
        pop     ebp     ;basepointteri alkuperäisiin arvoihin
        mov     eax,0   ;Lopetetaan ohjelma nollalla
        ret

Tehtävä 1

Täydennä fibocalc.asm siten, että sillä voidaan laskea enemmän kuin kaksi ensimmäistä lukua.

Tehtävä 2

Oppikirjojen mukaan parametrit välitetään pinossa. Käytännössä näin ei kuitenkaan ole, vaan kääntäjät käyttävät rekistereitä mahdollisimman paljon hyväkseen. Muuta koodia siten, että käytät parametrin välitykseen rekisteriä EDI. Huomaa, että kokonaan ilman pinoa et selviä, sillä EDI:n arvo ei saa muuttua aliohjelmakutsun aikana. Joudut siis käyttämään paikallista muuttujaa apuna.