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

时间:2014-10-21 06:00:47

标签: c assembly

我正在学习汇编,我想了解如何使用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指令完成它。

上述代码中的情况并非如此。我没有看到任何堆栈初始化。

谢谢!

1 个答案:

答案 0 :(得分:13)

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

首先,xy将替换为其常量表达式:

    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