2011-06-22 97 views
0

任何人都可以告诉我x86 ASM中的以下代码是干什么的?它只是一个大文件的一部分,但这只是让我失望。x86汇编代码

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) 

具体来说,

  • 什么最初%EDI在第13行?
  • 为什么代码引用-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; 
} 
+0

如果你有C代码,你不知道它在做什么?你究竟想问什么? –

回答

7

什么是最初在%edi 13行?

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


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

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


而究竟是什么线16吗?

线16是一个数组索引操作:

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

的AT & T语法用于存储器寻址是有些奇怪寻找。它打破了如:

段覆盖:签订偏移(基准,指数,规模)

在你的情况下,数组的地址被用作偏移字段,你有没有基地寄存器或段覆盖,标度为4,正在使用的变址寄存器为rax。这打破了喜欢的东西沿着这类似于C的伪代码的行:

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

背后有什么在32位寄存器和64位寄存器后面的开关(例如智慧第15行的情况)?

我没有看到第15行这样的事情,但它做的原因是因为你的函数使用了大量的int - 因为int是32位的,编译器使用32位的寄存器。无关紧要或编译器正在使用临时寄存器,它将选择本机64位大小。

+0

最后一行更像'eax = *((int *)((char *)a + rax * 4));'。代码考虑了int的大小。 – cHao

+0

@ cHao,是的,这是一个更明显的描述。我在示例中压缩了一些冗余,以使其与原始代码的某些外表匹配。我会更新它。 –

+0

非常感谢。这清理了很多东西。 :) @cHao,也谢谢你:) – arkati