Here, take a look:
; printlong.asm
bits 64
default rel
section .text
; Entry: RAX = n (signed long).
; Destroy: RAX, RBX, RCX, RDX, RSI, RDI, R8 and R9.
;
global printlong
printlong:
lea rsi,[rsp + 16] ; Points to the end of string.
sub rsp,40 ; allocate space on stack for string.
mov r8,rax ; Holds a copy of n to test for signal later.
xor ecx,ecx ; ECX will count how many chars in the buffer.
mov rbx,10 ; divisor on RBX.
mov r9,rax ; Need R9 in loop below (holds que quotient).
.loop:
mov rax,r9 ; Gets old quotient.
cqo ; Extends sign of RAX to RDX.
idiv rbx
mov r9,rax ; New quotient in R9.
test rdx,rdx ; Remainder is negative?
jns .notnegative ; No. don't negate.
neg rdx ; Yes. negate.
.notnegative:
add dl,'0' ; store '0' + remainder and decrease pointer.
mov [rsi],dl
dec rsi
inc ecx ; one more character on buffer.
test rax,rax ; Quotient is zero?
jnz .loop ; No. keep in loop.
mov edx,ecx ; Move size to EDX because of syscall.
test r8,r8 ; n is negative?
jns .skipsignal ; no. everything is ok.
mov byte [rsi],'-' ; yes. add '-' to buffer.
dec rsi
inc edx
.skipsignal:
inc rsi ; Points to the beginning of buffer.
mov eax,1 ; sys_write
mov edi,eax ; stdout
syscall
add rsp,40 ; deallocate space from stack.
ret
; test.asm
bits 64
default rel
section .rodata
lf: db `\n`
section .text
extern printlong
global _start
_start:
mov rax,-123
call printlong
; Prints final '\n'.
mov eax,1
mov edi,eax
lea rsi,[lf]
mov edx,eax
syscall
; exit(0).
xor edi,edi
mov eax,60
syscall
# Makefile
test: test.o printlong.o
ld -s -o $@ $^
test.o: test.asm
nasm -felf64 -o $@ $<
printlong.o: printlong.asm
nasm -felf64 -o $@ $<
.PHONY: clean
clean:
rm *.o
To test:
$ make
nasm -felf64 -o test.o test.asm
nasm -felf64 -o printlong.o printlong.asm
ld -s -o test test.o printlong.o
$ ./test
-123
$
[]s
Fred