C编译器是否优化了汇编中的函数,以便最大限度地减少堆栈的使用?

时间:2014-12-22 03:19:45

标签: assembly calling-convention

我开始学习汇编(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代码中出现的相反顺序推送参数。
  • 然后你保存对框架和堆栈指针的引用(我猜测你可以递归地执行此操作,但是还没有达到目前尚未知道的程度)。
  • 然后你计算你的功能需要的任何东西。
  • 然后,将堆栈和帧指针弹出堆栈

因此,为了获得更多使用堆栈和函数调用约定的实际经验,我希望看到现有的C编译器如何将函数调用转换为汇编(gcc和clang,使用this这很棒)。但是,我没有看到调用约定模式(我到目前为止所见过的每种资源都是这样做的方式)!

检查出来,这是从一些C:

生成的相对复杂的汇编代码

https://gist.github.com/lancejpollard/a1d6a9b4820473ed8797

通过该C代码,有几个级别的嵌套函数调用。但是输出汇编代码并没有显示推/弹堆栈模式!

所以问题是,这些编译器是否只是优化程序集以便避免这样做? (因为,这个示例C代码,虽然有一些嵌套函数,但仍然非常简单,所以我想编译器可以预先计算很多东西)。或者我错过了什么?

2 个答案:

答案 0 :(得分:1)

一般来说:

  • 如果一个函数可能被另一个目标文件中的某个东西调用(例如,该函数不是static并且您正在创建一个目标文件),那么编译器必须遵守调用约定(以便链接可以工作)。
  • 如果您正在编译调试,那么典型的调试器将使用堆栈帧来查找事物(输入参数,局部变量等),并且性能不是高优先级,因此尊重调用约定是个好主意。

对于所有其他情况,编译器可以完全忽略调用约定并执行它认为更有效的任何操作(包括在寄存器中传递参数而不使用堆栈或帧指针,还包括完全内联函数)。

然而:

  • 对于某些情况(例如函数指针和具有可变数量参数的函数),编译器可能无法做很多事情,并且可能只使用标准调用约定(即使它不严格需要)。
  • 编译器可以生成一个或多个不同版本的函数(例如,一个尊重其他目标文件中的代码可以使用的调用约定,以及另一个不遵循调用约定的优化版本)。 / LI>
  • 链接器可以进行编译器无法进行的优化(链接时间优化),包括修改编译器无法优化的函数的调用约定(因为编译器没有足够的潜在调用者知识)但是链接器可以(作为链接器“看到”整个程序)。

答案 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