【问题标题】:What is the difference between these two function prologue instruction sequences?这两个函数序言指令序列有什么区别?
【发布时间】:2015-09-25 10:45:32
【问题描述】:

测试在32-bit x86。我用gcc 4.2编译了代码,优化级别o2。我把C代码编译成二进制,然后用objdump反汇编。

这里有两个用于函数序言的指令序列:

0804a6f0 <quotearg_n>:
804a6f0:       8b 44 24 04             mov    0x4(%esp),%eax
804a6f4:       b9 ff ff ff ff          mov    $0xffffffff,%ecx
804a6f9:       8b 54 24 08             mov    0x8(%esp),%edx
804a6fd:       c7 44 24 04 40 e1 04    movl   $0x804e140,0x4(%esp)
804a704:       08 
804a705:       e9 c6 fa ff ff          jmp    804a1d0 <quotearg_n_options>
804a70a:       8d b6 00 00 00 00       lea    0x0(%esi),%esi


0804a730 <quotearg>:
804a730:       83 ec 1c                sub    $0x1c,%esp
804a733:       8b 44 24 20             mov    0x20(%esp),%eax
804a737:       c7 04 24 00 00 00 00    movl   $0x0,(%esp)
804a73e:       89 44 24 04             mov    %eax,0x4(%esp)
804a742:       e8 a9 ff ff ff          call   804a6f0 <quotearg_n>
804a747:       83 c4 1c                add    $0x1c,%esp
804a74a:       c3                      ret
804a74b:       90                      nop
804a74c:       8d 74 26 00             lea    0x0(%esi,%eiz,1),%esi

请注意,在函数quotearg 中,寄存器esp 在用于访问堆栈并获取一些参数之前会减少0x1c。准确地说,根据我的经验,我认为sub 然后access 模式对于使用O2 编译的指令是很常见的。

但是,注意在函数quotearg_n中,寄存器esp直接加上0x4来访问堆栈。 (我认为地址0x804a6f0的指令的意思是将调用站点的返回地址注册eax,对吗..?)根据我的观察,第一个函数使用的模式很少见,大约gcc 使用 O2 编译的中等大小 C 程序的 5%。

所以这是我的问题:

为什么编译器生成函数序言指令的方式类似于quoterag_n?前三个指令从地址0x804a6f0 开始的确切含义是什么?

为什么编译器不总是按照sub 然后access 模式生成函数序言指令? (如quoterag

我说清楚了吗?非常感谢

【问题讨论】:

  • 可能有助于显示生成此代码的代码或对 quotearg_n_options 代码的引用(可能是 GNUlib 可移植库或许多等效库)。知道这些函数是如何定义的,我们就可以准确地知道它在做什么。

标签: c gcc assembly x86


【解决方案1】:

带有sub %esp 的那个是典型的make-some-room-on-the-stack,然后将args 放在那里,然后调用一个函数。您还可以这样做以保留空间以将本地变量从寄存器溢出到内存。

第一个是尾调用优化,在将一些值加载到寄存器后跳转到quotearg_n_options。最终调用的 args 与我们输入 quotearg_n 时堆栈中的 args 相同。

它可以解决这个问题,因为它不需要任何堆栈空间来存储局部变量。

我不确定它到底对4(%esp) 做了什么。我认为这就是其中一个 args 所在的地方,因为它将它设置为一个常数。 IIRC,(%esp) 是返回地址,4(%esp) 是第一个参数。它将第一个参数设置为常量,可能是缓冲区的地址。我不清楚它为什么会做其他一些事情,除非它跳到quotearg_n_options 的中间,%edx 中的值可能很重要。 (并解释为什么它将堆栈中的其他参数加载到被调用者可以破坏的寄存器中。

【讨论】:

  • 这可能是针对 win32 __vectorcall ABI 的 gcc,其中前两个参数位于 ecxedx
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
  • 2011-02-20
  • 2013-04-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多