Converting 32-bit Fibonacci nasm code to 64-bit

2019-08-05 17:43发布

问题:

I'm a newbie in writing assembly code and I need some help.

My task is to write a program in NASM (on Linux), which computes n-th Fibonacci number, where n is read from STDIN with read syscall and converted to int/long with C atoi/atol. The calculated number will be written to STDOUT (I can use C printf).

I managed to write the working 32-bit code and I'm stuck at converting it to 64-bit (using 64-bit registers, 64-bit long int). I tried to do it naively (changing eax -> rax, esp -> rsp and so on), but the only thing I get is segfault.

EDIT: Typo is fixed

EDIT2: Any ideas, how to use 64-bit Integers, to show higher than 46-th Fibonacci number?

Here's the code:

section .data
        format: db      '%d', 0xA


section .bss
        buffer resb 8 
        bufferLength equ $-buffer; 

section .text

extern printf
extern atoi

global main

main:
        call fib 

fib:
        mov rax, 3 
        mov rbx, 0 
        mov rcx, buffer
        mov rdx, bufferLength 
        int 0x80 

        push 0
        push buffer 
        call atoi
        add rsp, 8

        push rbx
        mov rcx, rax
        xor rax, rax
        xor rbx, rbx
        inc rbx

        call print

exitProg:
        mov rbx, 0 
        mov rax, 1 
        int 0x80 

print:
        push rax
        push rcx

        push rax
        push format
        cmp rcx, 1
        je lastPrint
        add rsp, 8

        pop     rcx
        pop     rax

        mov     rdx, rax   
        mov     rax, rbx    
        add     rbx, rdx        
        dec     ecx           
        jnz     print    

        pop     rbx       

lastPrint:
        call printf
        add rsp, 8
        call exitProg

Thanks in advance.

回答1:

Your functions are not really functions as they don't return. You should consider rewriting them. If you are using the C library, it's better practice to return from main instead of using the exit system call. Also, it's advisable to use the C library I/O functions, if allowed.

In 64 bit mode, you typically access system calls using the syscall instruction, although the int 0x80 interface is also available for compatibility. Note that system call numbers are different from 32 bit.

In addition, even the the calling convention is different (both user and system call), some arguments are passed in registers and the stack needs to be kept aligned. See the ABI documentation for details.

I have a hard time understanding the logic of the print code especially the crazy stack manipulations. Also note that the pop rbx line will never be reached because rcx is checked for being 1 earlier, hence after decrementing it will never be zero.

You also have a typo, bufor. Finally, your format string is in the text section. While that works, I am guessing you wanted it in .data, you just have misplaced the directive (which is on the first line of your file).

I expect most of the above apply to the original 32 bit code too.

Update here is a possible implementation, now with 64 bit result (works up to n=93) and using XADD (thanks to Frank Kotler):

section .data
format:
        db      "%lu", 10, 0

section .bss
        buffer resb 8
        bufferLength equ $-buffer

section .text

default rel ; use rip relative addressing (optional)
extern printf
extern atoi

global main

main:
        sub rsp, 8              ; stack alignment

        ; note: this should be a call to libc read function
        ; but apparently assignment forces us to use syscall
        xor eax, eax            ; syscall number for "read" is 0
        xor edi, edi            ; fd 0, stdin
        lea rsi, [buffer]       ; buf
        mov edx, bufferLength   ; length
        syscall

        lea rdi, [buffer]
        call atoi

        mov edi, eax            ; pass returned value from atoi
        call fib

        lea rdi, [format]
        mov rsi, rax            ; the returned value from fib
        xor eax, eax            ; no xmm registers used
        call printf

        xor eax, eax            ; return zero
        add rsp, 8
        ret

fib:
        mov eax, edi
        sub edi, 1
        jle fib_done            ; f(0)=0, f(1)=1
        xor ecx, ecx            ; f(n-1)
        mov eax, 1              ; f(n)
fib_loop:
        xadd rax, rcx
        sub edi, 1
        jnz fib_loop

fib_done:
        ret