3

我试图了解如何为 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 现在被推送到堆栈中的不同偏移量,而之前的片段中没有指针。

问题 #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 字节),那也会很有帮助。猜猜这应该是为了做一些簿记练习,但确切的原因是什么?

谢谢,

4

2 回答 2

0

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

于 2013-04-28T18:41:01.510 回答
0

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

于 2013-04-28T19:38:19.597 回答