Well, I dunno. The general rule is that if you allocate more space than you need, your code might be "bloated". If you allocate less than you need, it's a bug.
Here are a couple examples, one without any subroutines, one with...
; convert one number to ascii and print it
; nasm -f elf32 myfile.asm
; ld -o myfile myfile.o (-melf_i386 for 64-bit systems)
global _start
section .bss
buffer resb 16 ; nice round number
section .text
_start:
mov eax, 1234567 ; our number
mov ebx, 10 ; divisor
xor ecx, ecx ; counter
top:
xor edx, edx ; zero edx for the div
div ebx ; quotient in eax, remainder in edx
push edx ; our digit
inc ecx ; count 'em
test eax, eax ; is quotient zero yet?
jnz top ; no? do more
mov edx, ecx ; we're done with edx - save the length
mov edi, buffer
poploop:
pop eax
add eax, '0' ; convert digit to character
stosb
loop poploop
mov byte [edi], 10 ; throw in a linefeed for neater display
inc edx ; and add it to the length
mov ecx, buffer
mov ebx, 1 ; stdout
mov eax, 4 ; sys_write
int 80h
exit:
xor ebx, ebx ; exitcode zero
mov eax, 1 ; sys_exit
int 80h
; convert several numbers to ascii (signed, right-justified)
; nasm -f elf32 myfile.asm
; ld -o myfile myfile.o (-melf_i386 for 64-bit syatems)
global _start
FIELD_WIDTH equ 12 ; 10 digits and a minus sign... rounded up :)
section .data
num1 dd 123456
num2 dd -123414
section .bss
buf1 resb FIELD_WIDTH
buf2 resb FIELD_WIDTH
bufres resb FIELD_WIDTH
section .text
_start:
mov eax, [num1]
mov esi, buf1
mov ecx, FIELD_WIDTH
call binasc
mov eax, [num2]
mov esi, buf2
mov ecx, FIELD_WIDTH
call binasc
; add 'em togtether...
mov eax, [num1]
add eax, [num2]
mov esi, bufres
mov ecx, FIELD_WIDTH
call binasc
; now print 'em out
mov ecx, buf1
mov edx, FIELD_WIDTH
call write_stdout
call linefeed
mov ecx, buf2
mov edx, FIELD_WIDTH
call write_stdout
call linefeed
mov ecx, bufres
mov edx, FIELD_WIDTH
call write_stdout
call linefeed
exit:
xor ebx, ebx
mov eax, 1
int 80h
;-------------------
;--------------------
; from Chuck Crayne - RIP, Chuck.
;convert binary to ascii
;call with eax = signed binary number
; esi = address of output string
; ecx = length of output string
;returns esi = 1st printed digit
; ecx = no of digits printed (includes sign if any)
; other registers preserved
binasc: push edx
push ebx
push edi
push eax
mov edi,esi ;save start of string
ba1: mov byte [esi],' ' ;fill string with blanks
inc esi
loop ba1
mov ebx,10 ;initialize divisor
or eax,eax ;value negative?
jns ba2 ;no problem
neg eax ;make it positive
ba2: xor edx,edx ;clear high part of dividend
div ebx ;divide by 10
add dl,'0' ;convert to ascii digit
dec esi ;step backwards through buffer
mov [esi],dl ;store digit
inc ecx
cmp esi,edi ;out of space
jz ba4 ;yes - quit
or eax,eax ;all digits printed?
jnz ba2 ;no - keep trucking
pop eax ;get original value
or eax,eax ;negative?
jns ba3 ;no - quit
dec esi ;place for sign
mov byte [esi],'-'
inc ecx ;add to char count
ba3: pop edi
pop ebx
pop edx
ret
ba4: pop eax
jmp ba3
;-------------------
;--------------------
write_stdout:
; call with ecx = buffer, edx = lemgth
; returns length
push ebx
mov ebx, 1
mov eax, 4
int 80h
pop ebx
ret
;--------------------
;----------------
linefeed:
push eax
push ecx
push edx
push 10 ; linefeed
mov ecx, esp ; my stack is my buffer
mov edx, 1 ; length
call write_stdout
pop edx ; dummy pop to free the LF
pop edx
pop ecx
pop eax
ret
;---------------------
They do different things, so it's kinda comparing apples with oranges...
Best,
Frank