如何解决了解汇编、nasm、x86 中的 printf 函数我不知道为什么这段代码没有打印出任何东西
BITS 64;
global main
extern printf
section .text
main: ; This is called by the C library startup code
push rbx ; required to make printf 16-byte aligned.
; For Now we only do this once!
push qword 300
call sum
mov rdi,dfmt ; set 1st parameter (format)
mov rsi,rax ; set 2nd parameter (low byte)
xor rax,rax ; because printf is varargs we must clear rax
call printf ; printf(format,current_number)
pop rbx ; must restore rbx for Linux
ret ; Return from main back into C library wrapper
sum:
push rbp ; retrieve parameter
push rbx ; save prevIoUs
mov rbp,rsp
add rsp,24 ; create room for integer
mov rbx,[rbp] ; rbx = param
cmp rbx,0 ; if (n <= 0)
je base
dec rbx ; decrement rbx to place in stack
push rbx ; put (rbx - 1) in stack
inc rbx
call sum ; calculate sum(n - 1)
add rax,rbx
pop rbx
jmp end
base:
mov rax,1
end:
pop rbx
pop rbp
ret
dfmt:
db "%ld",10,0
解决方法
让我们一点一点地经历这个。
在 main
函数中,您有 push qword 300
。我认为这是为了将参数传递给 sum
?如果是这样......那不是你在做什么。我建议改为遵循 AMD64 调用约定并使用 mov rdi,300
然后使用 call sum
,这会期望在 rdi
中找到它的第一个参数。
无论如何,在 sum
中,您要做的第一件事是 push rbp
,这是非常标准的。那么你push rbx
。这是一个被调用者保存的寄存器,很好。然后是 mov rbp,rsp
,这也是非常标准的。
现在你释放一些带有add rsp,24
的堆栈,我不明白。堆栈向低地址增长,因此要保留一些堆栈,您可以从 rsp
中减去。但也许这不是你在做什么?
现在我真的很困惑。您执行 mov rbx,[rbp]
,但由于 rbp
没有被 main
函数修改,因此它不会指向我们想要的任何位置。我只能假设这是在堆栈上获取参数的一些尝试?
老实说,在这一点上我很难过。
通常使用以下样板启动您的函数。
push rbp
mov rbp,rsp
原因是为了保护栈。现在所有引用都可以针对 rbp
完成,它在您的代码中永远不会改变(它总是指向您的堆栈帧)。它是一个被调用者保存的寄存器,所以无论如何我们都必须保存它,并在设置它之前在堆栈上这样做。
通常使用以下样板结束您的函数。
mov rsp,rbp
pop rbp
ret
按照 AMD64 调用约定的要求,这会将堆栈指针和 rbp
恢复到它们在入口时的位置。这有一个同义词:leave
。下面的代码是等价的。
leave
ret
现在,当您使用 printf
(或任何可能使用 xmm
寄存器的函数)时,您还必须确保在调用之前堆栈在 16 字节边界上对齐。您可以假设堆栈在进入 main
时对齐。 push rbp
会将它搞砸(减少 8 位),但是当您执行 call printf
时,您将再推 8 个字节(返回地址)并加速!堆栈已对齐。
我最后的建议是使用 AMD64 调用约定而不是使用堆栈。将参数放入rdi
,获取rax
中的返回值。
如果不知道您要做什么,我无法提供更多帮助。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。