【问题标题】:C assembly language ATT walkthrough? [duplicate]C汇编语言ATT演练? [复制]
【发布时间】:2018-04-12 21:00:12
【问题描述】:

我有一个简单的 c 程序,它将三个变量相乘和相加并返回结果。我已在 32 位机器上将代码编译成汇编语言(ATT 格式)。我正在尝试学习汇编代码,虽然我可以理解其中的一些行,但我需要帮助理解为什么例如 leal (%edx, %edx, 2), %edx 会在下面的代码中完成,比如结果是什么,它会完成什么?

汇编代码

.file   "calc.c"
        .text
.globl calc
        .type   calc, @function
calc:
        pushl   %ebp                   #prolog
        movl    %esp, %ebp             #prolog
        movl    8(%ebp), %edx          #move %ebp +8 into %edx 
        movl    16(%ebp), %ecx         #move %ebp +16 into %ecx
        leal    (%edx,%edx,2), %edx
        movl    12(%ebp), %eax
        leal    (%edx,%eax,2), %eax
        movl    %ecx, %edx
        sall    $4, %edx
        subl    %ecx, %edx
        addl    %edx, %eax
        popl    %ebp
        ret
        .size   calc, .-calc
        .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
        .section        .note.GNU-stack,"",@progbits

C 程序

#include <stdio.h>
int calc(int x, int y, int z){
    return 3*x + 2*y + 15*z;
}
int main(void) {
    int x = 2;
    int y = 6;
    int z = 11;

    int result = calc(x,y,z);

    printf("x=%d, y=%d, z=%d, result=%d\n", x,y,z,result);
    return 0;
}

有人可以帮我从序言开始追踪问题。

【问题讨论】:

  • 您是否尝试过阅读手册?手册对lea 指令有何评论? (a,b,c) 操作数表示法是怎么说的?
  • 告诉编译器进行优化。读取未优化的编译器生成的程序集很痛苦。
  • 使用调试器、显示寄存器和单步执行单个汇编指令应该可以揭示您正在寻找的大部分内容。
  • 另见at&t syntax :) 来自x86 tag wiki 的链接。如果您发现它更具可读性,gcc -masm=intel 也会产生 intel 语法输出。

标签: c assembly x86 32-bit


【解决方案1】:

也许最好用 C 函数代码来解释:

int calc(int x, int y, int z){
    return 3*x + 2*y + 15*z;
}

查看参数 x。它乘以 3,因此在汇编代码中很容易识别:

movl    8(%ebp), %edx

....

leal    (%edx,%edx,2), %edx
movl    12(%ebp), %eax
leal    (%edx,%eax,2), %eax

它将参数 x 的值移动到 edx 中。栈帧中参数 x 的地址为 ebp+8。然后稍后使用 leal 将 edx 添加到 2*edx 并将值存储在 edx 中。等于 3*x。
然后将参数 y 加载到 eax 中,您可以轻松识别,因为 y 是 32 位 int,因此它比 x 的起始地址高 4 个字节。
接下来 leal 将 edx(即 3*x)与 2*eax(即 2*y)相加,并将结果存储在 eax 中,因此在 eax 中您有 3*x + 2*y。
等等……

【讨论】:

  • 嗯,这比我尝试做的更有意义:0x8 + 0x8*2 = %edx address
【解决方案2】:

我建议您首先不要优化您的代码。您的优化器正在与您玩游戏。如果您的系统以相反的顺序推送参数

8(%ebp) = x = edx
12(%ebp) = y = eax
16(%ebp) = z = ecx

使用汇编游戏:

(%edx,%edx,2) = edx + 2 x edx = 3 x edx  (3 x X)
(%edx,%eax,2)  = edx + 2 x eax = (3 x X + 2 * y)

  movl    %ecx, %edx
  sall    $4, %edx = (16 x Z)
  subl    %ecx, %edx = 15 x Z

【讨论】:

  • gcc -O0 输出。您可以通过每个 C 语句之间的溢出/重新加载来判断,以支持使用调试器更改 C 变量,并使用 gdb 的 jump 命令。 lea 在 x86 中如何乘以 3。如果针对代码大小进行优化,您可以 imul $3, (mem), %eax,但 gcc 在 -O0 选择不这样做,并使用其常规方法乘以小常数。
猜你喜欢
  • 2013-02-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-16
  • 1970-01-01
  • 2014-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多