Macos 这个汇编函数的序言/尾声代码对rbp/rsp/leave做了什么?
我刚刚开始学习使用GCC编译器为mac汇编代码。不幸的是,如果你是一个初学者,学习如何做到这一点的资源非常有限。我终于找到了一些简单的示例代码,我可以开始认真思考,并使它正确地组装和运行。代码如下:Macos 这个汇编函数的序言/尾声代码对rbp/rsp/leave做了什么?,macos,gcc,assembly,stack,x86-64,Macos,Gcc,Assembly,Stack,X86 64,我刚刚开始学习使用GCC编译器为mac汇编代码。不幸的是,如果你是一个初学者,学习如何做到这一点的资源非常有限。我终于找到了一些简单的示例代码,我可以开始认真思考,并使它正确地组装和运行。代码如下: .text # start of code indicator. .globl _main # make the main function vi
.text # start of code indicator.
.globl _main # make the main function visible to the outside.
_main: # actually label this spot as the start of our main function.
push %rbp # save the base pointer to the stack.
mov %rsp, %rbp # put the previous stack pointer into the base pointer.
subl $8, %esp # Balance the stack onto a 16-byte boundary.
movl $0, %eax # Stuff 0 into EAX, which is where result values go.
leave # leave cleans up base and stack pointers again.
ret
注释解释了代码中的一些事情(我有点理解第2-5行的功能),但我不理解其中的大部分含义。我确实了解什么是寄存器以及每个寄存器的基本用途(
rbp
、rsp
、esp
和eax
)以及它们的大小,我也了解(通常)堆栈是什么,但这仍然超出了我的理解范围。有人能告诉我这到底是怎么回事吗?另外,有谁能为我指出一个适合初学者的好教程的方向吗 堆栈是一种如下的数据结构。日常生活中的堆栈(我指的是计算机之外的堆栈)向上增长,而x86和x86-64处理器中的堆栈则向下增长。请参阅(但请考虑代码示例是英特尔语法中的32位x86代码,而您的代码是AT&T语法中的64位x86-64代码)
那么,您的代码是做什么的(我在这里用英特尔语法解释):
将rbp
推到堆栈中,实际上从rsp
中减去8(因为rbp
的大小是8字节),然后将rbp
存储到[ss:rsp]
因此,在英特尔语法中,推送rbp实际上是这样做的:
sub rsp, 8
mov [ss:rsp], rbp
然后:
这是显而易见的。只需将rsp
的值存储到rbp
中即可
subl $8, %esp
ret
从esp
中减去8,并将其存储到esp
中。实际上,这是代码中的一个bug,即使它在这里没有引起任何问题。x86-64中以32位寄存器(eax
,ebx
,ecx
,edx
,ebp
,esp
,esi
或edi
)作为目标的任何指令都会设置相应64位寄存器的最高位32位(rax
,rbx
,rcx
,rdx
,rbp
,rsp
,rsi
或rdi
)归零,导致堆栈指针指向低于4 GiB限制的某个位置,有效地做到了这一点(在英特尔语法中):
编辑:添加了子esp的后果,8
如下
但是,在内存小于4 GiB的计算机上,这不会导致任何问题。在内存大于4 GiB的计算机上,这可能会导致分段错误。在下面的代码中保留
会将一个正常值返回到rsp
。通常在x86-64代码中,您不需要esp
never(可能不包括一些优化或调整)。要修复此错误:
subq $8, %rsp
到目前为止,这些指令是标准的输入序列(根据堆栈使用情况替换$8
)(但请再次注意,它使用具有Intel语法的32位x86程序集,而不是具有AT&T语法的64位x86-64程序集)
然后:
这是显而易见的。将0存储到eax
。这与堆栈无关
leave
这相当于mov-rsp,rbp
,然后是pop-rbp
subl $8, %esp
ret
最后,这将
rip
设置为存储在[ss:rsp]
中的值,有效地将代码指针返回到调用此过程的位置,并将8添加到rsp如果您不知道汇编,x86是最不适合首先学习的。拥有硬件是我听到的最不适合首先学习x86的借口(你不想第一次学习硬件)。如果您想通过做一些有用的事情来学习,并且您要在x86上评测某些东西,那么您最好先学习x86 asm。现代用户空间x86不错。是的,如果您试图编写操作系统,而不是查看普通程序的编译器输出,这会很复杂,但不要先这样做。有很多很好的链接可供参考和学习g中的手册。
leave
ret