Kirjautuminen

Haku

Tehtävät

Koodit: Assembly: Fibonaccin lukujono Linuxilla

Kirjoittaja: Päärynämies

Kirjoitettu: 14.11.2007 – 19.04.2013

Tagit: matematiikka, ohjelmointitavat, koodi näytille, vinkki, Linux

kikkareen koodiesimerkin (https://www.ohjelmointiputka.net/koodivinkit/25070-assembly-fibonaccin-lukujono) innoittamana Fibonaccin lukujonon laskua Linuxilla. Esittelee komentoriviargumenttien ja Linuxin systeemikutsujen (system calls) käyttöä. AT&T syntaksilla kirjoitettu. Koodia yritetty mahdollisimman hyödyllisesti kommentoida, käskyjen toiminta kuitenkin jätetty suurimmaksi osin lukijan tietämyksen varaan.

Funktio print_number tulostaa luvun numero numerolta. Tulostettava luku jaetaan kymmenellä ja jakojäännös laitetaan pinoon. Kun luku menee alle kymmeneen, niin aletaan tulostaa jakojäännöksiä pinosta. Näin saadaan tulostettua useamman numeron sisältävä luku oikein. Funktio on rekursiivinen, mutta se olisi voitu toteuttaa myös pitämällä kirjaa pinossa olevien jäännöstä määrästä ja käyttää hyppykäskyjä silmukassa.

Koodi ei tarkista oliko käyttäjän haluama määrä termejä oikeasti luku vai sisälsikö se muitakin merkkejä. Ohjelma todennäköisesti kaatuu, jos se ei ole luku. Tarkistus olisi helppo toteuttaa, mutta jätin sen tekemättä, koska se ei mielestäni ollut oleellista koodiesimerkin kannalta. Lukija voi harjoitustyönä lisätä tarkistuksen halutessaan.

Ei tarvitse kirjastoja kääntämiseen.

Kääntäminen:
as fibs.s -o fibs.o
ld fibs.o -o fibs -s
Käyttö:
./fibs x
jossa x haluttujen termien määrä

fibs.s

#Laskee käyttäjän haluaman määrän Fibonaccin lukujonon termejä alkaen
#ensimmäisestä. Kun termi on suurempi kuin 2^32, niin ohjelma ei enää
#toimi oikein, johtuen siitä, että ohjelma käyttää 32-bittisiä
#rekistereitä lukujen laskemiseen.
#Kääntäminen:
#as fibs.s -o fibs.o
#ld fibs.o -o fibs -s
#Käyttö:
#./fibs x
#jossa x on haluttujen termien määrä.
#-s ei pakollinen ld:lle, mutta poistaa turhaa tietoa suoritettavasta
#tiedostosta ja pienentää sen kokoa huomattavasti. Ohjelman koko vain
#456 tavua

#Määritellään joitakin vakioita selkeyttämään.
.equ LINUX_SYSCALL, 0x80
.equ SYSCALL_EXIT, 1
.equ SYSCALL_WRITE, 4
.equ STDOUT, 1

.section .bss
	.lcomm char, 1	#varataan tulostettavalle numerolle muistia

.section .text
.globl _start

#Tulostaa %eax:ssä saamansa luvun.
#Funktio on rekursiivinen.
.type print_number, @function
print_number:
	xorl %edx, %edx
	movl $10, %ebx
	divl %ebx	#jaetaan %eax %ebx:llä. %eax sisältää osamäärän
	pushl %edx	#%edx sisältää jakojäännöksen
	cmpl $0, %eax
	jz no_call
		call print_number
no_call:
	popl %eax
	addl $48, %eax	#48 on ascii taulukossa 0, 49 on 1 jne.
	call print
	ret

#Tulostettavan merkin ascii arvo välitetään %eax:ssä
.type print,@function
print:
	leal char, %ecx
	movb %al, (char)
	movl $SYSCALL_WRITE, %eax
	movl $STDOUT, %ebx
	movl $1, %edx
	int $LINUX_SYSCALL
	ret

#Funktio, joka muuttaa ascii-merkkijonon luvuksi.
#Merkkijonon osoite välitetään rekisterissä %eax.
#Funktio palauttaa luvun %eax:ssä.
.type atoi, @function
atoi:
	pushl %ebx
	pushl %ecx
	pushl %esi
	movl %eax, %esi
	xorl %eax, %eax
	movl $10, %ebx
	cld		#%esi kasvaa yhdellä jokasen lodsb käskyn jälkeen
loop1:
	lodsb	#Ladataan %esi:n osoittamasta muistipaikasta tavu %eax:ään
	cmpl $0, %eax
	je end_loop1
	xchg %eax, %ecx
	mul %ebx
	subl $48, %ecx
	addl %ecx, %eax
	xchg %eax, %ecx
	jmp loop1
end_loop1:
	movl %ecx, %eax
	popl %esi
	popl %ecx
	popl %ebx
	ret

_start:
	movl (%esp), %eax	#argc %eax:ään
	cmpl $2, %eax 		#Syöttikö käyttäjä tarpeeksi argumenttejä?
	jb exit
	movl 8(%esp), %eax	#argv[1] %eax:ään
	call atoi
	movl %eax, %ecx	#haluttujen lukujen määrä on nyt %ecx:ssä
	xorl %eax, %eax	#sarjan ensimmäinen luku on 0
	movl $1, %ebx	#sarjan toinen luku on 1
	fib_loop:
		pusha	#tallennetaan kaikki rekisterit
		call print_number
		movl $32, %eax #32 on välilyönti
		call print
		popa	#palautetaan kaikki rekisterit
		pushl %eax
		addl %ebx, %eax
		popl %ebx
		loop fib_loop
exit:
	movl $0, %ebx	#Ohjelman palauttama arvo
	movl $SYSCALL_EXIT, %eax
	int $LINUX_SYSCALL

Kommentit

moptim [14.11.2007 16:47:20]

#

Kylpä nyt on assenplyvinkit suosiossa ^_^

tejeez [14.11.2007 21:38:04]

#

Ja millä seuraavaksi? x86-vinkkejä fibonaccin jonon tulostukseen on jo nyt tässä kaksi kappaletta peräkkäin, joten välillä joku voisi laittaa jotain muuta.

Ihan hyvä vinkki kyllä kymmenjärjestelmän tulostuksesta ja lukemisesta (sekä vinkeissä vähemmän käytetystä at&t-syntaksista).

TsaTsaTsaa [02.12.2007 15:56:02]

#

./fibs 0 toimii kivasti :)

EDIT: Niin no sanotaanhan selostuksessa toki, että argumenttia ei tarkisteta millään lailla.

Dude [17.12.2007 17:25:24]

#

miten saa käännettyä fasmilla?

Päärynämies [12.01.2008 00:17:26]

#

Vinkki ei taida suoraan kääntyä fasmilla, koska joka assembleri tuntuu käyttävän vähän omaa syntaksiaan erilaisten vakioiden ja muiden määrittelyssä. Suurin osa suosituimmista assemblereista myös käyttää Intelin syntaksia, eikä AT&T syntaksia. Koodin muuntaminen fasmin käyttämään syntaksiin ei pitäisi olla hankalaa, jos vain osaa AT&T syntaksia ja osaa tarvittaessa as:n manuaalia kurkata. Monet pitävät AT&T syntaksia sekavampana tai vaikeampana, mutta itse pidän siitä enemmän.

Mukava myös tietää, että joku on kokeillut ihan kääntää ja ajaa koodivinkkiäni.

Kirjoita kommentti

Muista lukea kirjoitusohjeet.
Tietoa sivustosta