(x64 Nasm) Writeline function on Linux

468 views Asked by At

I'm trying to make a printeline fuction, but the cmp fails when I am comparing the value from rsp address.

This is where the generic print function is:

    print:
        push    rdx  
        push    rcx  
        push    rbx  
        push    rax  

call stringlen ;calls stringlen. new return address assigned to rbx

mov rdx, rax ;move rax (containing string length) to rdx
pop rax        ; restore original rax argument value (string address)

mov rcx, rax ; move msg address to rcx
mov rbx, 1    ; stdout
mov rax, 4    ;opcode 4 print
int 80h       ;linux interrupt

pop rbx       ;restore original return address to rbx
pop rcx       ; restore value of rcx
pop rdx       ;restore value of rdx
ret

Here is the printline fuction. It calls print to print the message first. It then pushes linefeed onto the stack to get the address of it. Then it calls print again with the linefeed address stored in rax to print it.

   ;prints msg with a line feed
    printline:
        call    print  ;print the message

        push    rax
        mov rax, 0Ah  ;move linefeed into rax
        push    rax   ;push rax onto the stack
        mov rax,rsp   ;get the address of linefeed from rsp
        call    print ;print the linefeed
        mov rdx, 1
        mov rcx, rax
        mov rbx, 1
        mov rax, 4
        int 80h
        pop rax
        pop rax
        ret
    ;gets string length
    stringlen:
        push    rbx ;push return address to stack
        mov rbx, rax  ;rax holds the argument-> msg address

I think the issue is here:

    nextchar:  ;do the counting
        cmp byte [rax], 0h   ; When comparing address from rsp, zero flag is set

The zero flag is set and it jumps to finished instead of inc and looping back:

        jz  finished
        inc rax
        jmp nextchar

    finished:
       sub  rax, rbx  ;store the new argument rax as msg length
       pop  rbx  ;mov return address back into rbx
       ret  ;go to return address

This is in main.asm where I am calling printline:

    %include "stdio.asm"
    section .data
    msg db  "Print message 1:Hello world", 0h

    section .text
    global  _start

   _start:
   mov  rax, msg
   call printline  ;msg is printed but no linefeed

   mov  rax, 0
   call return

I have ran it through gdb and the rsp and rax seems to be pointing to the correct value (0x0a). Not really sure why cmp set the zero flag here. :(

1

There are 1 answers

2
Jester On

64 bit mode does not use int 80h, that's the 32 bit system call interface. If you are lucky, it might work if the pointers happen to be within range but it's not recommended. However the stack is usually outside of that range, which is why your code doesn't work. The code in print should look like:

print:
    push    rdx
    push    rcx
    push    rbx
    push    rax

    call stringlen ; calls stringlen

    mov rdi, 1    ; stdout
    pop rsi       ; restore original rax argument value (string address)
    mov rdx, rax  ; move rax (containing string length) to rdx
    mov rax, 1    ; sys_write
    syscall

    pop rbx       ; restore value of rbx
    pop rcx       ; restore value of rcx
    pop rdx       ; restore value of rdx
    ret

Adjust the save/restore code as necessary. You seem to be confused about rbx, why do you keep calling it "return address"?

PS: Not sure what the additional sys_write inside the printline is supposed to do.