将32位Fibonacci nasm代码转换为64位

时间:2012-12-15 13:15:49

标签: assembly segmentation-fault x86-64 nasm fibonacci

我是编写汇编代码的新手,我需要一些帮助。

我的任务是在NASM(在Linux上)编写一个程序,该程序计算第n个Fibonacci数,其中n从STDIN读取,读取系统调用并使用C atoi / atol转换为int / long。计算出的数字将写入STDOUT(我可以使用C printf)。

我设法编写了工作的32位代码,我坚持将其转换为64位(使用64位寄存器,64位长整数)。我试图天真地做(改变eax - > rax,esp - > rsp等),但我唯一得到的是段错误。

编辑:错字是固定的

EDIT2:任何想法,如何使用64位整数,显示高于第46个斐波纳契数?

以下是代码:

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

提前致谢。

1 个答案:

答案 0 :(得分:3)

您的功能不是真正的功能,因为它们不会返回。你应该考虑重写它们。如果您使用的是C库,最好从main返回,而不是使用exit系统调用。此外,如果允许,建议使用C库I / O函数。

在64位模式下,您通常使用syscall指令访问系统调用,尽管int 0x80接口也可用于兼容性。请注意,system call numbers与32位不同。

此外,即使调用约定不同(用户和系统调用),一些参数也在寄存器中传递,堆栈需要保持对齐。有关详细信息,请参阅ABI文档。

我很难理解print代码的逻辑,特别是疯狂的堆栈操作。另请注意,永远不会到达pop rbx行,因为rcx之前已经检查过1,因此在递减之后它永远不会为零。

您还有一个拼写错误bufor。最后,您的格式字符串位于文本部分。虽然这有效,但我猜你想要它.data,你只是错误地放置了指令(位于文件的第一行)。

我希望上面的大部分内容也适用于原来的32位代码。

更新这是一个可能的实现,现在有64位结果(最多工作n = 93)并使用XADD(感谢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