我正在学习汇编,我想了解如何从 C 代码生成汇编。
我创建了以下虚拟 C 代码:
#include <stdio.h>
int add(int x, int y){
int result = x + y;
return result;
}
int main(int argc, char *argv[]){
int x = 1 * 10;
int y = 2 * 5;
int firstArg = x + y;
int secondArg = firstArg / 2;
int value;
value = add(firstArg, secondArg);
return value;
}
得到如下汇编代码
.file "first.c"
.text
.globl add
.type add, @function
add:
.LFB39:
.cfi_startproc
movl 8(%esp), %eax
addl 4(%esp), %eax
ret
.cfi_endproc
.LFE39:
.size add, .-add
.globl main
.type main, @function
main:
.LFB40:
.cfi_startproc
movl $30, %eax
ret
.cfi_endproc
.LFE40:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",@progbits
我很惊讶 main 中的所有这些算术运算在哪里消失了? 我不明白我们是如何从无处获得 30 美元的(好吧,我想这是 add 函数的返回值,但为什么我没有看到任何获取此值的命令,实际上我看到返回值已经被推送到 eax 中add 函数,那么为什么我们需要再次将 $30 移动到 eax 呢?)。 所有本地主要变量都在哪里声明?我特地创建了其中的5个,看看一个是如何入栈的。
你能帮我理解那些.LFE39 .LFB40: .LFB39: 是什么意思吗?
我已经准备好这本书了,但它并没有为我阐明这个案例。 实际上书上说所有函数都必须从堆栈初始化开始:
pushl %ebp
movl %esp, %ebp
以及当函数结束时,它需要用 pop 指令完成它。
上面的代码不是这样的。我没有看到任何堆栈初始化。
谢谢!
最佳答案
您正在编译启用优化。 GCC 足够聪明,可以在编译时执行所有这些计算,并用一个简单的常量替换所有无用的代码。
首先,x
和 y
将被替换为它们的常量表达式:
int x = 10;
int y = 10;
然后,使用这些变量的地方将改为获取它们的常量值:
int firstArg = 20;
int secondArg = 10;
接下来,您的 add
函数又小又普通,因此它肯定会被内联:
value = firstArg + secondArg;
现在这些也是常量,所以整个事情将被替换为:
int main(int argc, char *argv[]) {
return 30;
}
虽然大多数函数都会有一个如您所展示的序言,但您的程序什么都不做 而是返回 30。更具体地说,它不再使用任何局部变量,也不再调用其他函数。因此 main
不需要调用堆栈上的帧或保留空间。因此,编译器无需发出序言/结尾。
main:
movl $30, %eax
ret
这些是您的程序将运行的唯一两条指令(C 运行时启动代码除外)。
另外请注意,由于您的add
函数未标记为static
,因此编译器必须假定外部人员可能会调用它。出于这个原因,我们仍然在生成的程序集中看到 add
,即使没有人调用它:
add:
movl 8(%esp), %eax
addl 4(%esp), %eax
ret
关于c - 在理解从 C 代码生成的基本汇编代码方面需要帮助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26479853/