【问题标题】:Add two numbers together in asm [duplicate]在asm中将两个数字相加[重复]
【发布时间】:2020-07-18 01:31:16
【问题描述】:

我已经将下面的 c 程序编译到 asm 中,看看它使用了哪些指令。我在 C 中拥有的是:

int add(int num1, int num2) {
    int num3 = num1 + num2;
    return num3;
}

我对指令“应该是”的想法(根据我对 asm 的非常有限的了解)是:

  1. 加载(两个 4 字节 int 变量到内存中)。
  2. 添加(两个内存位置),然后 -
  3. 将总和存储在第三个内存位置。
  4. 返回值并停止执行。

编译时,我对它所做的所有mov 操作感到惊讶:

add:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-20], edi
        mov     DWORD PTR [rbp-24], esi
        mov     edx, DWORD PTR [rbp-20]
        mov     eax, DWORD PTR [rbp-24]
        add     eax, edx
        mov     DWORD PTR [rbp-4], eax
        mov     eax, DWORD PTR [rbp-4]
        pop     rbp
        ret

有人可以带我浏览一下这里的 asm 代码并指出为什么它如此频繁地使用 mov 代码吗?这是一个例子:here

【问题讨论】:

  • 你是否使用了任何编译器标志,例如-O3
  • @Ackdari 不据我所知,但我使用 Godbolt 编译它,所以它可能会在其中抛出一些标志(您可以查看上面的链接)。
  • 如果您转到标有“编译器选项”的框并输入-O3,您会看到生成的代码更改为lea eax, [rdi+rsi]
  • asm 视图上方是编译器标志的文本字段,如果您在其中输入 -O3(即所有优化),asm 代码变得更加简约。

标签: c assembly x86


【解决方案1】:

这看起来像是在尽可能低的优化设置下专门编译的代码。它所做的是将参数(在寄存器ediesi 中)存储到堆栈内存(rbp - offset)中,然后将它们重新加载到寄存器eaxedx 中以添加它们,将结果存储回来进入堆栈内存中[rbp - 4]int num3,然后重新加载以在eax 中返回结果。

其中很多都是多余的,而且很容易:

add:
    add edi, esi
    mov eax, edi
    ret

或者在实践中gcc -O1 or higher实际上是

add:
    lea    eax, [rdi+rsi]
    ret

gcc/clang 默认为 -O0,它为一致的调试进行反优化,将变量保存在 C 语句之间的内存中,而不是寄存器中。详情请见Why does clang produce inefficient asm with -O0 (for this simple floating point sum)?

【讨论】:

  • 感谢您的解释。另外,如果int只有4个字节长,为什么指针偏移量是20和24?
  • @David542 堆栈帧包含多位信息,包括传入的参数以及要返回的地址、指向父堆栈帧的指针和其他一些东西。-20 和 -24是从堆栈的当前底部到函数参数的距离。看这里:stffrdhrn.github.io/software/embedded/openrisc/2018/06/08/…
猜你喜欢
  • 2016-10-12
  • 2019-12-20
  • 1970-01-01
  • 1970-01-01
  • 2019-10-15
  • 2010-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多