我正在学习汇编,我想了解如何使用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
我很惊讶所有主要的算术运算在哪里消失了? 我不明白我们是如何从无处获得30美元的(好吧,我想它是来自add函数的返回值,但是为什么我没有看到任何得到这个值的命令,实际上我看到返回值已被推送到eax in添加功能,为什么我们需要再次将30美元转移到eax?)。 所有当地主要货物都在哪里申报?我特意创建了其中的5个以查看如何将其推入堆栈。
你能帮我理解那些是什么吗.LFE39 .LFB40:.LFB39:是什么意思?
我准备好了这本书,但它并没有为我澄清这个案子。 实际上book说所有函数都必须从堆栈初始化开始:
pushl %ebp
movl %esp, %ebp
当函数结束时,它需要用pop指令完成它。
上述代码中的情况并非如此。我没有看到任何堆栈初始化。
谢谢!
答案 0 :(得分:13)
您正在编译并启用了优化。 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