了解汇编中的 printf 函数,nasm,x86。我不知道为什么这段代码没有打印出任何东西
Understanding the printf function in assembly, nasm, x86. I don't know why this code isn't printing anything out
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
这会将堆栈指针和 rbp
恢复到它们在入口时的状态,这是 AMD64 调用约定所要求的。这个有一个同义词:leave
。下面的代码是等价的。
leave
ret
现在,当您使用 printf
(或任何可能使用 xmm
寄存器的函数)时,您还必须确保堆栈在您之前在 16 字节边界上对齐称呼。您可以假设堆栈在进入 main
时对齐。 push rbp
会把它搞砸(减去 8),但是当你执行 call printf
时,你会再压入 8 个字节(return 地址)并且很快!堆栈已对齐。
我最后的建议是使用 AMD64 调用约定而不使用堆栈。把参数放在rdi
,得到return的值在rax
.
在不知道你想要做什么的情况下,我无法提供更多帮助。
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
这会将堆栈指针和 rbp
恢复到它们在入口时的状态,这是 AMD64 调用约定所要求的。这个有一个同义词:leave
。下面的代码是等价的。
leave
ret
现在,当您使用 printf
(或任何可能使用 xmm
寄存器的函数)时,您还必须确保堆栈在您之前在 16 字节边界上对齐称呼。您可以假设堆栈在进入 main
时对齐。 push rbp
会把它搞砸(减去 8),但是当你执行 call printf
时,你会再压入 8 个字节(return 地址)并且很快!堆栈已对齐。
我最后的建议是使用 AMD64 调用约定而不使用堆栈。把参数放在rdi
,得到return的值在rax
.
在不知道你想要做什么的情况下,我无法提供更多帮助。