【问题标题】:x86 assembly codex86 汇编代码
【发布时间】:2011-06-22 17:12:33
【问题描述】:

谁能告诉我 x86 ASM 中的以下代码是做什么的?它只是一个较大文件的一部分,但正是这一点让我感到沮丧。

find_max:
  6 .LFB0:
  7         .cfi_startproc
  8         pushq   %rbp
  9         .cfi_def_cfa_offset 16
 10         movq    %rsp, %rbp
 11         .cfi_offset 6, -16
 12         .cfi_def_cfa_register 6
 13         movl    %edi, -20(%rbp)
 14         movl    -20(%rbp), %eax
 15         cltq
 16         movl    a(,%rax,4), %eax
 17         movl    %eax, -4(%rbp)
 18         movl    -20(%rbp), %eax
 19         movl    %eax, -8(%rbp)

具体来说,

  • 第 13 行的 %edi 最初是什么?
  • 为什么代码引用 -20(%rbp)?
  • 那么第 16 行究竟做了什么?
  • 切换 32 位寄存器和 64 位寄存器背后的智慧是什么(例如第 15 行的情况)?

我反汇编得到的 C 代码如下所示:

extern int a[];

int find_max(int n)
{
    int max = a[n];
    int pos = n;
    int x;

    while (n > 0)
    {
        n--;
        x = a[n];

        if (x > max)
        {
            max = x;
            pos = n;
        }
    } 
    return pos;
}

【问题讨论】:

  • 如果你有 C 代码,你不知道它在做什么吗?你到底想问什么?

标签: assembly x86 disassembly


【解决方案1】:

第 13 行的 %edi 最初是什么?

rdi 是 AMD/Linux 64 位 ABI 的第一个参数传递寄存器。此代码中使用了edi,因为您的函数采用 32 位 int 参数。


为什么代码引用了-20(%rbp)

它将传入的参数保存到堆栈中;大概你正在编译低优化或没有优化,所以每个变量都得到一个真实的内存地址。如果您打开优化,您可能会看到这些操作消失了。


那么第 16 行究竟做了什么?

第 16 行是数组索引操作:

movl    a(,%rax,4), %eax

用于内存寻址的 AT&T 语法看起来有点奇怪。它分解为:

segment-override:signed-offset(base,index,scale)

在您的情况下,数组的地址被用作偏移字段,您没有基址寄存器或段覆盖,比例为4,使用的索引寄存器为rax。这可以分解为类似 C 类伪代码的内容:

eax = *(int *)((char *)a + (rax * 4))

在 32 位寄存器和 64 位寄存器后面切换背后的智慧是什么(例如在第 15 行的情况下)?

我在第 15 行没有看到类似的内容,但这样做的原因是因为您的函数使用了很多 int - 因为 int 是 32 位类型,编译器使用的是 32 位寄存器。无关紧要或编译器使用临时寄存器时,它会选择本机 64 位大小。

【讨论】:

  • 最后一行更像eax = *((int*)((char*) a + rax*4));。该代码考虑了 int 的大小。
  • @cHao,是的,这是一个更明显的描述。我在示例中压缩了其中的一些冗余,以使其与原始代码的某些外观相匹配。我会更新的。
  • 非常感谢。这让事情清楚了很多。 :) @cHao,也谢谢你 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-20
  • 1970-01-01
  • 1970-01-01
  • 2016-02-08
相关资源
最近更新 更多