具有指针作为局部变量的函数的汇编指令

时间:2013-04-28 18:30:43

标签: c assembly stack gnu x86-64

我试图了解如何为c生成程序集。我写了一个示例程序并将其拆解为相同的程序。

int main()
{
int a = 100;
}

汇编生成:

pushq   %rbp     #
movq    %rsp, %rbp   #,
subq    $48, %rsp    #,
call    __main   #
movl    $100, -4(%rbp)   #, a
leave
ret

这对我来说非常简单。但是当我在其中包含指针时,我不理解程序集。

C计划:

int main()
{
int a = 100;
int *p = &a;
}

汇编生成:

pushq   %rbp     #
movq    %rsp, %rbp   #,
subq    $48, %rsp    #,
call    __main   #
movl    $100, -12(%rbp)  #, a
leaq    -12(%rbp), %rax  #, tmp59
movq    %rax, -8(%rbp)   # tmp59, p
leave
ret

我不明白为什么局部变量a现在被推送到堆栈中的不同偏移量,而之前的snip没有指针。

问题#2: 如果我有4个局部变量,我的堆栈帧是subq $ 48,%rsp,但如果我将其中一个局部变量转换为指针,则它是subq $ 64。为什么会这样。

C代码:

int main()
{
int a = 100;
int *p = &a;
int b = 10;
int c = 20;
}

大会:

pushq   %rbp     #
movq    %rsp, %rbp   #,
subq    $64, %rsp    #,
call    __main   #
movl    $100, -20(%rbp)  #, a
leaq    -20(%rbp), %rax  #, tmp59
movq    %rax, -8(%rbp)   # tmp59, p
movl    $10, -12(%rbp)   #, b
movl    $20, -16(%rbp)   #, c
leave
ret

如果你们可以解释为什么堆栈帧对于没有局部变量的主函数是2 * 16字节对齐(32字节)也会有所帮助。猜猜应该是一些记账练习,但究竟是什么原因?

谢谢,

2 个答案:

答案 0 :(得分:0)

编译器不是简单地将代码逐行从c转换为汇编。优化编译器将对代码进行大量分析,尝试执行诸如删除永远不会执行的代码,优化循环性能以及优化堆栈/内存使用等操作。当编译器决定在哪里分配内存以及在哪里存储变量时,它知道a和p两者并将它们放在它认为最好的地方。

答案 1 :(得分:0)

好吧,在x86_64中,堆栈指针始终保持16字节对齐(因此使用sse 16字节加载/存储指令将是最有效的)。指针是8个字节,只需要8个字节对齐,而整数是4个字节,只需要4个字节对齐。堆栈框架中的局部变量的顺序是完全未指定的,但通常编译器将首先布置具有最大对齐限制的那些,然后是更灵活的那些(为了最有效地打包)。编译器也可以为其他东西保留空间(在调用中溢出寄存器和传出参数的空间),并依赖优化器死代码来消除不需要的东西(所以如果你在没有优化的情况下编译,你会看到很多堆栈框架中显然未使用的空间。)