我对堆栈的目的进行了一些哲学思考,经过一些编码后,我弄清楚了它的强度。唯一在我胃里的就是它是如何与功能一起工作的?我尝试使用通用寄存器创建一些简单的函数来添加两个数字,但我想这不是它在 C 中的工作方式,例如。所有参数、局部变量和结果存储在哪里?
您将如何将其重写为汇编程序?(C 的编译器将如何重写它?)
int function(int a, int &b, int *c){
return a*(b++)+(*c);
}
我知道这个例子有点糟糕..但是这样我就可以理解所有的可能性
您正在寻找的是有关调用约定的信息。函数的调用和返回方式取决于很多因素,包括处理器架构、编译器和操作系统。调用者和被调用者必须就约定达成一致,以便正确传递参数和返回值。
首先,引用 ( int&) 不在 C 中,只是在 C++ 中。
如果您想查看 gcc 的幕后情况,请使用该-S标志。你不需要有一个实际的程序。
g++ -S func.c
创建一个func.s包含(减去标题等,在 x86 盒子上)的文件:
.text
.globl __Z8functioniRiPi
__Z8functioniRiPi:
LFB2:
pushq %rbp
LCFI0:
movq %rsp, %rbp
LCFI1:
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
movq %rdx, -24(%rbp)
movq -16(%rbp), %rax
movl (%rax), %edx
movl %edx, %ecx
imull -4(%rbp), %ecx
movq -24(%rbp), %rax
movl (%rax), %eax
addl %eax, %ecx
incl %edx
movq -16(%rbp), %rax
movl %edx, (%rax)
movl %ecx, %eax
leave
ret
请注意 C++ 名称修饰 ( __Z8functioniRiPi)。现在我们给 g++-O2标志:
.text
.align 4,0x90
.globl __Z8functioniRiPi
__Z8functioniRiPi:
LFB2:
pushq %rbp
LCFI0:
movq %rsp, %rbp
LCFI1:
movl (%rsi), %ecx
movl %ecx, %eax
imull %edi, %eax
addl (%rdx), %eax
incl %ecx
movl %ecx, (%rsi)
leave
ret
-O3给出相同的代码;真的没有什么可以优化的了。
玩组装很开心。^_^
Aaron 关于调用约定的说法是正确的答案。对于我个人对该主题的探索,我发现Smashing the Stack For Fun and Profit是一个很好的练习,可以扮演堆栈框架的角色,以及当它被损坏时会发生什么。Finlay 我向黑客推荐汇编入门,它涵盖了重要的汇编器概念以及您可以使用调试器做的有趣事情。