我试图了解如何为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字节)也会有所帮助。猜猜应该是一些记账练习,但究竟是什么原因?
谢谢,
答案 0 :(得分:0)
编译器不是简单地将代码逐行从c转换为汇编。优化编译器将对代码进行大量分析,尝试执行诸如删除永远不会执行的代码,优化循环性能以及优化堆栈/内存使用等操作。当编译器决定在哪里分配内存以及在哪里存储变量时,它知道a和p两者并将它们放在它认为最好的地方。
答案 1 :(得分:0)
好吧,在x86_64中,堆栈指针始终保持16字节对齐(因此使用sse 16字节加载/存储指令将是最有效的)。指针是8个字节,只需要8个字节对齐,而整数是4个字节,只需要4个字节对齐。堆栈框架中的局部变量的顺序是完全未指定的,但通常编译器将首先布置具有最大对齐限制的那些,然后是更灵活的那些(为了最有效地打包)。编译器也可以为其他东西保留空间(在调用中溢出寄存器和传出参数的空间),并依赖优化器死代码来消除不需要的东西(所以如果你在没有优化的情况下编译,你会看到很多堆栈框架中显然未使用的空间。)