我开始学习汇编(OSX上的NASM中的x86-64),现在正在探索函数的外观。
大多数资源解释了如何调用约定"工作展示的例子如下:
// c code
MyFunction1(a, b);
// assembly code
main:
push a
push b
push rbp ; save frame pointer on stack
mov rsp, rbp ; save stack pointer in frame pointer
xor rax, rax ; set function return value to 0.
call _MyFunction
mov rbp, rsp ; restore stack pointer
pop rbp ; restore frame pointer
ret ; return to calling function
(我刚刚在合并了几个资源之后做了这个,所以可能存在很多问题,但这不在主要问题之内。)。
调用cdecl calling convention等约定的要点是:
因此,为了获得更多使用堆栈和函数调用约定的实际经验,我希望看到现有的C编译器如何将函数调用转换为汇编(gcc和clang,使用this这很棒)。但是,我没有看到调用约定模式(我到目前为止所见过的每种资源都是这样做的方式)!
检查出来,这是从一些C:
生成的相对复杂的汇编代码https://gist.github.com/lancejpollard/a1d6a9b4820473ed8797
通过该C代码,有几个级别的嵌套函数调用。但是输出汇编代码并没有显示推/弹堆栈模式!
所以问题是,这些编译器是否只是优化程序集以便避免这样做? (因为,这个示例C代码,虽然有一些嵌套函数,但仍然非常简单,所以我想编译器可以预先计算很多东西)。或者我错过了什么?
答案 0 :(得分:1)
一般来说:
static
并且您正在创建一个目标文件),那么编译器必须遵守调用约定(以便链接可以工作)。对于所有其他情况,编译器可以完全忽略调用约定并执行它认为更有效的任何操作(包括在寄存器中传递参数而不使用堆栈或帧指针,还包括完全内联函数)。
然而:
答案 1 :(得分:0)
您可以让C编译器输出assember源代码而不是可链接对象。在linux上,cc -S file.c
将创建一个包含汇编代码的file.s。尝试一个小的测试功能,以及各种级别的优化。识别调用约定很容易,它与你的伪代码非常相似。
file.c:
foo(int x)
{
return x+1;
}
file.s:
.file "t.c"
.text
.globl foo
.type foo, @function
foo:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
addl $1, %eax
popl %ebp
ret
.size foo, .-foo
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"
.section .note.GNU-stack,"",@progbits