Sunteți pe pagina 1din 8

Numarator pana la 10

Numrarea nu este implicit n asamblare. Mai nti trebuie s se furnizeze o adres


pentru sys_write pentru a putea ncrca un registru cu un numr i apoi apela
funcia print. In al doilea rnd, numerele i irurile sunt lucruri diferite n asamblare.
irurile sunt reprezentate folosind valori ASCII; nu putem tipari un numr, trebuie
mai nti s l convertim n simbolul asociat, de ex. reprezentarea numrului 1
este 49 in ASCII. De fapt, dac se adaug 48 la numr se poate obine codul ASCII
al acestuia.
Pentru a scrie numra se utilizeaz registrul ECX. Apoi se adaug 48 la valoarea din
numrtor folosind funcia ADD pentru a se obine codul ASCII, care este apoi
ncrcat in stack folosind PUSH. Aceast valoare este folosit pentru a da funciei
print adresa de la care s tipreasc. Odat ce se termin de numrat pn la
10ieim din bucl i apelm funcia quit.
; Hello World Program (Count to 10)
; Compile with: nasm -f elf helloworld-10.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 helloworld-10.o -o
helloworld-10
; Run with: ./helloworld-10
%include

'functions.asm'

SECTION .text
global _start
_start:
mov

ecx, 0

nextNumber:
inc
ecx

; ecx is initalised to zero.

; increment ecx

mov
add
push
mov
call

eax, ecx
; move the address of our integer into eax
eax, 48
; add 48 to our number to convert from integer to ascii for printing
eax
; push eax to the stack
eax, esp
; get the address of the character on the stack
sprintLF
; call our print function

pop
cmp
jne

eax
; clean up the stack so we don't have unneeded bytes taking up space
ecx, 10
; have we reached 10 yet? compare our counter with decimal 10
nextNumber
; jump if not equal and keep counting

call

quit

Pentru execuie se utilizeaz secvena:


~$ nasm -f elf helloworld-10.asm
~$ ld -m elf_i386 helloworld-10.o -o helloworld-10
~$ ./helloworld-10
1
2
3

4
5
6
7
8
9
:

Execuia se ncheie cu :, de ce?

Numrtor pn la 10 (itoa)
Exmplul anterior s-a ncheiat cu : pentru c am dat funciei print caracterul ASCII
58 cnd, de fapt, dac doream s scriem 10 trebuia s dm ca argument
4948. Asta nseamn c nu putem aduga 48 numerelor, ci trebuie s le mprim
cu 10 pentru ca apoi s efectum oeraia pentru fiecare valoare individual.
Pentru aceasta vom scrie dou subrutine noi, iprint i iprintLF. Funciile vor fi
utilizate cnd se dorete tiprirea reprezentrilor ASCII ale numerelor. Acest lucru se
realizeaz prin transferarea numrului n EAX, apoi se iniializeaz un numrtor n
ECX. Se mparte numrul la 10 n mod repetati de fiecare dat se convertete
restul ntr-un string adugnd 48. Valoarea este PUSH n stack. Atunci cnd nu se
mai poate face mprirea se intr n cea de-a doua faz. n aceast bucl de
tiprire se tiprete irul convertit din stack i POP valorile. Prin POP stack-ul mut
ESP la elementul urmtor, i de fiecare dat cnd se tiprete o valoare se
descrete contorul ECX. Dup ce toate numerele au fost tiparite se iese din
execuie.
Instruciunile DIV i IDIV se execut mprnd orice este n EAX cu valoarea dat
instruciunii. Ctul este lsat n EAX iar restul este in EDX (care se numea iniial data
register).
De exemplu:
mov
mov
idiv
idiv

eax, 10 ; move
esi, 10 ; move
esi
; divide
esi
; divide

10 into eax
10 into esi
eax by esi (eax will equal 1 and edx will equal 0)
eax by esi again (eax will equal 0 and edx will equal 1)

Fisierul functions.asm
;-----------------------------------------; void iprint(Integer number)
; Integer printing function (itoa)
iprint:
push
eax
; preserve eax on
push
ecx
; preserve ecx on
push
edx
; preserve edx on
push
esi
; preserve esi on
mov
ecx, 0
; counter of how
divideLoop:
inc
mov
mov
idiv

ecx
edx, 0
esi, 10
esi

the stack to be restored after


the stack to be restored after
the stack to be restored after
the stack to be restored after
many bytes we need to print in

; count each byte to print - number of characters


; empty edx
; mov 10 into esi
; divide eax by esi

function
function
function
function
the end

runs
runs
runs
runs

add
edx, 48
; convert
after a divide instruction
push
edx
; push edx
cmp
eax, 0
; can the
jnz
divideLoop
; jump if
printLoop:
dec
mov
call
pop
cmp
jnz
pop
pop
pop
pop
ret

edx to it's ascii representation - edx holds the remainder


(string representation of an intger) onto the stack
integer be divided anymore?
not zero to the label divideLoop

ecx
eax, esp
sprint
eax
ecx, 0
printLoop

; count down each byte that we put on the stack


; mov the stack pointer into eax for printing
; call our string print function
; remove last character from the stack to move esp forward
; have we printed all bytes we pushed onto the stack?
; jump is not zero to the label printLoop

esi
edx
ecx
eax

;
;
;
;

restore
restore
restore
restore

esi
edx
ecx
eax

from
from
from
from

the
the
the
the

value
value
value
value

we
we
we
we

pushed
pushed
pushed
pushed

onto
onto
onto
onto

the
the
the
the

stack
stack
stack
stack

at
at
at
at

the
the
the
the

start
start
start
start

;-----------------------------------------; void iprintLF(Integer number)


; Integer printing function with linefeed (itoa)
iprintLF:
call
iprint
; call our integer printing function
push
eax
in this function
mov
eax, 0Ah
push
eax
mov
eax, esp
call
sprint
pop
eax
pop
eax
ret

; push eax onto the stack to preserve it while we use the eax register
; move 0Ah into eax - 0Ah is the ascii character for a linefeed
; push the linefeed onto the stack so we can get the address
; move the address of the current stack pointer into eax for sprint
; call our sprint function
; remove our linefeed character from the stack
; restore the original value of eax before our function was called

;-----------------------------------------; int slen(String message)


; String length calculation function
slen:
push
ebx
mov
ebx, eax
nextchar:
cmp
jz
inc
jmp
finished:
sub
pop
ret

byte [eax], 0
finished
eax
nextchar
eax, ebx
ebx

;-----------------------------------------; void sprint(String message)


; String printing function
sprint:
push
edx
push
ecx
push
ebx
push
eax
call
slen
mov
pop

edx, eax
eax

mov

ecx, eax

mov
mov
int

ebx, 1
eax, 4
80h

pop
pop
pop
ret

ebx
ecx
edx

;-----------------------------------------; void sprintLF(String message)


; String printing with line feed function
sprintLF:
call
sprint
push
mov
push
mov
call
pop
pop
ret

eax
eax, 0AH
eax
eax, esp
sprint
eax
eax

;-----------------------------------------; void exit()


; Exit program and restore resources
quit:
mov
ebx, 0
mov
eax, 1
int
80h
ret

Fiierul helloworld-itoa.asm
; Hello World Program (Count to 10 itoa)
; Compile with: nasm -f elf helloworld-itoa.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 helloworld-itoa.o -o
helloworld-itoa
; Run with: ./helloworld-itoa
%include

'functions.asm'

SECTION .text
global _start
_start:
mov

ecx, 0

nextNumber:
inc
ecx
mov
eax, ecx
call iprintLF
cmp
ecx, 10
jne
nextNumber
call

; NOTE call our new integer printing function (itoa)

quit

Pentru execuie, secvena este:

~$ nasm -f elf helloworld-itoa.asm


~$ ld -m elf_i386 helloworld-itoa.o -o helloworld-itoa
~$ ./helloworld-itoa
1
2
3
4
5
6
7
8
9
10

Adunarea
n acest exemplu von aduna registrii EAX i EBX i vom lsa rspunsul n EAX. Mai
nti se utilizeaz MOV pentru a ncrca un ntreg (n cazul acesta 90), apoi vom
face MOV pentru un ntreg n EBX (n acest caz 9). Adunarea va fi realizat utiliznd
ADD, dup care tot ceea ce trebuie fcut este s se tipreasca rezultatul.
; Calculator (Addition)
; Compile with: nasm -f elf calculator-addition.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 calculator-addition.o -o
calculator-addition
; Run with: ./calculator-addition
%include

'functions.asm'

SECTION .text
global _start
_start:
mov
mov
add
call

eax, 90
; move our
ebx, 9
; move our
eax, ebx ; add ebx to
iprintLF
; call our

call

quit

first number into eax


second number into ebx
eax
integer print with linefeed function

Pentru executarea programului, secvena de comenzi este:


~$ nasm -f elf calculator-addition.asm
~$ ld -m elf_i386 calculator-addition.o -o calculator-addition
~$ ./calculator-addition
99

Scderea

Se va scdea valoarea din EBX din cea stocat n EAX. Mai nti se ncarc EAX i
EBX cu ntregii n acelai mod ca n exemplul anterior. Singura diferen este c se
va utiliza SUB, pstrnd rezultatul n EAX, dup care se afieaz rezultatul.

; Calculator (Subtraction)
; Compile with: nasm -f elf calculator-subtraction.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 calculator-subtraction.o -o
calculator-subtraction
; Run with: ./calculator-subtraction
%include

'functions.asm'

SECTION .text
global _start
_start:
mov
mov
sub
call

eax, 90
ebx, 9
eax, ebx
iprintLF

call

quit

;
;
;
;

move our
move our
subtract
call our

first number into eax


second number into ebx
ebx from eax
integer print with linefeed function

Pentru execuie secvena este:


~$ nasm -f elf calculator-subtraction.asm
~$ ld -m elf_i386 calculator-subtraction.o -o calculator-subtraction
~$ ./calculator-subtraction
81

nmulirea
Se va multiplica valoarea din EBX cu cea din EAX utiliznd instruciunea MUL.
Rezultatul este pstrat n EAX.
; Calculator (Multiplication)
; Compile with: nasm -f elf calculator-multiplication.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 calculator-multiplication.o
-o calculator-multiplication
; Run with: ./calculator-multiplication
%include

'functions.asm'

SECTION .text
global _start
_start:
mov
mov
mul
call

eax, 90
ebx, 9
ebx
iprintLF

; move our first number into eax


; move our second number into ebx
; multiply eax by ebx
; call our integer print with linefeed function

call

quit

Pentru execuie secvena este


~$ nasm -f elf calculator-multiplication.asm
~$ ld -m elf_i386 calculator-multiplication.o -o calculator-multiplication
~$ ./calculator-multiplication
810

mprirea
Vom mpri valoarea din EBX cu cea din EAX iar rezultatul va fi pstrat n EAX iar
restul n EDX.
; Calculator (Division)
; Compile with: nasm -f elf calculator-division.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 calculator-division.o -o
calculator-division
; Run with: ./calculator-division
%include

'functions.asm'

SECTION .data
msg1
db

' remainder '

; a message string to correctly output result

SECTION .text
global _start
_start:
mov
mov
div
call
mov
call
mov
call

eax, 90
ebx, 9
ebx
iprint
eax, msg1
sprint
eax, edx
iprintLF

call

quit

; move our first number into eax


; move our second number into ebx
; divide eax by ebx
; call our integer print function on the quotient
; move our message string into eax
; call our string print function
; move our remainder into eax
; call our integer printing with linefeed function

Pentru execuie secvena este:


~$
~$
~$
10

nasm -f elf calculator-division.asm


ld -m elf_i386 calculator-division.o -o calculator-division
./calculator-division
remainder 0

Calculator
Programul preia argumente de la linia de comand i le adun.

Programul preia numrul de argumente utiliznd POP, valoarea este stocat n ECX.
Se trece apoi prin argumente i acestea sunt convertite din ASCII in int utiliznd
funcia atoi i abia dup aceasta putem efectua adunarea.
Cum funcioneaza atoi
Se ia adresa irului i se mut n ESI, dup care se parcurge irul byte cu byte.
Pentru fiecare cifr se verifica valoarea ntre 48 57 i dac valoarea este linefeed
sau null terminating byte, adic am ajuns la sfritul irului.
Odat ce a fost parcurs irul se scade 48 din valoare, obinndu-se echivalentul
decimal, iar aceast valoare este adugat n

S-ar putea să vă placă și