试图从 g++ 中理解简单的反汇编代码

Posted

技术标签:

【中文标题】试图从 g++ 中理解简单的反汇编代码【英文标题】:Trying to understand simple disassembled code from g++ 【发布时间】:2017-01-27 10:30:23 【问题描述】:

我仍在努力使用 g++ 内联汇编器并试图了解如何使用它。

我从这里改编了一段代码:http://asm.sourceforge.net/articles/linasm.html(引自 gcc 信息文件中的“带有 C 表达式操作数的汇编器指令”部分)

static inline uint32_t sum0() 
   uint32_t foo = 1, bar=2;
   uint32_t ret;
   __asm__ __volatile__ (
      "add  %%ebx,%%eax" 
         : "=eax"(ret)              // ouput
         : "eax"(foo), "ebx"(bar)   // input
         : "eax"                    // modify
   );
   return ret;

我已经编译了禁用优化:

g++ -Og -O0 inline1.cpp -o test

反汇编的代码让我困惑:

(gdb) disassemble sum0
Dump of assembler code for function sum0():
   0x00000000000009de <+0>:   push   %rbp                  ;prologue...
   0x00000000000009df <+1>:   mov    %rsp,%rbp             ;prologue...
   0x00000000000009e2 <+4>:   movl   $0x1,-0xc(%rbp)       ;initialize foo
   0x00000000000009e9 <+11>:  movl   $0x2,-0x8(%rbp)       ;initialize bar
   0x00000000000009f0 <+18>:  mov    -0xc(%rbp),%edx       ;
   0x00000000000009f3 <+21>:  mov    -0x8(%rbp),%ecx       ;
   0x00000000000009f6 <+24>:  mov    %edx,-0x14(%rbp)      ; This is unexpected
   0x00000000000009f9 <+27>:  movd   -0x14(%rbp),%xmm1     ; why moving variables
   0x00000000000009fe <+32>:  mov    %ecx,-0x14(%rbp)      ; to extended registers?
   0x0000000000000a01 <+35>:  movd   -0x14(%rbp),%xmm2     ;
   0x0000000000000a06 <+40>:  add    %ebx,%eax             ; add (as expected)
   0x0000000000000a08 <+42>:  movd   %xmm0,%edx            ; copying the wrong result to ret
   0x0000000000000a0c <+46>:  mov    %edx,-0x4(%rbp)       ;    "     "    "     "     "  "
   0x0000000000000a0f <+49>:  mov    -0x4(%rbp),%eax       ;    "     "    "     "     "  "
   0x0000000000000a12 <+52>:  pop    %rbp                  ;
   0x0000000000000a13 <+53>:  retq   
End of assembler dump.

正如预期的那样,sum0() 函数返回了错误的值。

有什么想法吗?到底是怎么回事?如何正确处理?

-- 编辑-- 根据@MarcGlisse 评论,我尝试了:

static inline uint32_t sum0() 
   uint32_t foo = 1, bar=2;
   uint32_t ret;
   __asm__ __volatile__ (
      "add  %%ebx,%%eax" 
         : "=a"(ret)             // ouput
         : "a"(foo), "b"(bar)     // input
         : "eax"                 // modify
   );
   return ret;

似乎我一直在关注的教程具有误导性。输出/输入字段中的“eax”不是指寄存器本身,而是缩写表上的e、a、x缩写。

不管怎样,我还是不明白。上面的代码导致编译错误:“asm”操作数有不可能的约束。

我不明白为什么。

【问题讨论】:

启用优化可能会让事情更容易理解? "eax" 并不意味着你认为它做了什么,你想要“a”。并且无需将输出标记为已破坏。 请仔细阅读:“无需将输出标记为破坏”。 【参考方案1】:

x86 的扩展内联汇编约束在 official documentation 中列出。complete documentation 也值得一读。

如您所见,约束都是单个字母。foo 的约束“eax”指定了三个约束:

一个 一个寄存器。

x 任何 SSE 寄存器。

e 32 位有符号整数常量,或 ...

由于您告诉 GCC eax 已被破坏,因此无法将输入操作数放在那里,而是选择 xmm0

当编译器选择用于表示输入操作数的寄存器时,它不会使用任何被破坏的寄存器

proper constraint is simply "a". 您需要从clobbers中删除eax(顺便说一下,由于高位归零,它应该是rax)(并添加“cc”)。

【讨论】:

谢谢!我已经编辑了问题以显示结果代码 @Chocksmith 很高兴为您提供帮助。但是,您进行编辑是多余的,因为将我的答案标记为已接受是传达它解决了您的问题所需的全部内容。我正在回滚您的编辑以使其符合 SO 准则:) 它还将帮助未来的读者解决同样的问题

以上是关于试图从 g++ 中理解简单的反汇编代码的主要内容,如果未能解决你的问题,请参考以下文章

带注释的可执行文件反汇编

switch 语句的反汇编浅析

[反汇编]从双向链表中拆除其中一个结点的反汇编分析

for 循环的反汇编浅析

了解 Dalvik 代码的反汇编?

如何从核心转储的反汇编函数中找到局部变量的地址并显示其值