1

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

我的任务是在 NASM(在 Linux 上)中编写一个程序,它计算第 n 个斐波那契数,其中 n 是使用 read syscall 从 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

提前致谢。

4

1 回答 1

3

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

在 64 位模式下,您通常使用指令访问系统调用syscall,尽管该int 0x80接口也可用于兼容性。请注意,系统调用号不同于 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
于 2012-12-15T14:26:07.127 回答