This is my first attempt in 64-bit assembly under Linux. I am using FASM.
I am converting a 64-bit register hex value to string. It is working fine until it reaches the final digit. I can't figure out exactly what's wrong with my code. Maybe there is something about 64-programming that I don't know or with the syscall (I am a linux noob as well)
format ELF64 executable 3
entry start
segment readable executable
start:
mov rax,3c5677h ;final '7' is not displayed
push rax
call REG
;call line
xor edi,edi ;exit
mov eax,60
syscall
;----------------------------------
REG:push rbp ;stack frame setup
mov rbp,rsp
sub rsp,8 ;space for local char
mov rax,[rbp+16];arg
lea r9,[rsp-8] ;local char
mov rcx,16 ;divisor
mov rsi,16 ;16 hex digits for register
.begin: ;get the digit
xor rdx,rdx ;by division
div rcx ;of 16
push rdx ;from back to front
dec rsi
test rsi,rsi
jz .disp
jmp .begin
.disp: ;convert and display digit
inc rsi
pop rax ;In reverse order
add rax,30h ;convert digit to string
cmp rax,39h ;if alpha
jbe .normal
add rax,7 ;add 7
.normal:
mov [r9],rax ;copy the value
push rsi ;save RSI for syscall
mov rsi,r9 ;address of char
mov edx,1 ;size
mov edi,1 ;stdout
mov eax,1 ;sys_write
syscall
pop rsi ;restore RSI for index
cmp rsi,16
je .done
jmp .disp
.done:
add rsp,8 ;stack balancing
pop rbp
ret
Thanks in advance for your help.
I believe the problem printing the last digit comes from how you load r9. If on entry, rsp was 100. You subtract 8 (rsp = 92), then load r9 with rsp - 8 (r9 = 84). Presumably you meant r9 to 100, so try changing that to:
lea r9, [rsp+8]
For a more efficient solution, how about something more like this (assumes value in rbx):
mov r9, 16 ; How many digits to print
mov rsi, rsp ; memory to write digits to
sub rsp, 8 ; protect our stack
mov edx, 1 ; size is always 1
mov edi, 1 ; stdout is always 1
.disp:
rol rbx, 4 ; Get the next nibble
mov cl, bl ; copy it to scratch
and cl, 15 ; mask out extra bits
add cl, 0x30 ; Convert to char
cmp cl, 0x39 ; if alpha
jbe .normal
add cl, 7 ; Adjust for letters
.normal:
mov [rsi], cl ; copy the value
mov eax, 1 ; sys_write
syscall ; overwrites rcx, rax, r11
dec r9 ; Finished a digit
jnz .disp ; Are we done?
add rsp, 8 ; Done with the memory