需要帮助理解从C代码生成的基本汇编代码

Use*_*oon 3 c assembly

我正在学习汇编,我想了解如何使用C代码生成Assembly.

我创建了以下虚拟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;
}
Run Code Online (Sandbox Code Playgroud)

并得到以下汇编代码

.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
Run Code Online (Sandbox Code Playgroud)

而且我很惊讶所有那些主要的算术运算都消失了?我不明白我们是如何从无处获得30美元的(好吧,我想它是来自add函数的返回值,但是为什么我没有看到任何得到这个值的命令,实际上我看到返回值已被推送到eax in添加功能,为什么我们需要再次将30美元转移到eax?).所有当地主要货物都在哪里申报?我特意创建了其中的5个以查看如何将其推入堆栈.

你能帮我理解那些是什么吗.LFE39 .LFB40:.LFB39:是什么意思?

我准备好了这本书,但它并没有为我澄清这个案子.实际上书说所有功能必须从堆栈初始化开始:

  pushl   %ebp
  movl    %esp, %ebp
Run Code Online (Sandbox Code Playgroud)

当函数结束时,它需要用pop指令完成它.

在上面的代码中不是这种情况.我没有看到任何堆栈初始化.

谢谢!

Jon*_*art 13

您正在编译并启用了优化.GCC足够聪明,可以在编译时执行所有这些计算,并用一个简单的常量替换所有无用的代码.

首先,xy将被替换为自己的常量表达式:

    int x = 10;
    int y = 10;
Run Code Online (Sandbox Code Playgroud)

然后,使用这些变量的位置将获得其常量值:

    int firstArg = 20;
    int secondArg = 10;
Run Code Online (Sandbox Code Playgroud)

接下来,您的add功能很小而且微不足道,因此它肯定会被内联:

    value = firstArg + secondArg;
Run Code Online (Sandbox Code Playgroud)

现在这些也是常量,所以整个事情将被替换为:

int main(int argc, char *argv[]) {
    return 30;
}
Run Code Online (Sandbox Code Playgroud)

虽然大多数函数都会有一个像你所展示的序幕,但你的程序除了返回30之外什么都不做.更具体地说,它不再使用任何局部变量,也不会调用其他函数.因为这main不需要调用堆栈上的帧或保留空间.所以编译器不需要发出序言/尾声.

main:
    movl    $30, %eax
    ret
Run Code Online (Sandbox Code Playgroud)

这些是程序运行的唯一两条指令(除了C运行时启动代码).


请注意,由于您的add功能未标记static,编译器必须假设外部有人可能会调用它.出于这个原因,我们仍然add在生成的程序集中看到,即使没有人调用它:

add:
    movl    8(%esp), %eax
    addl    4(%esp), %eax
    ret
Run Code Online (Sandbox Code Playgroud)