c++ - 试图理解来自 g++ 的简单反汇编代码

标签 c++ gcc assembly g++ disassembly

我仍在努力使用 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”操作数具有不可能的约束。

我不明白为什么。

最佳答案

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

可以看到,约束都是单个字母。
foo 的约束“eax”指定了三个约束:

a
   The a register.

x
   Any SSE register.

e
   32-bit signed integer constant, or ...

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

When the compiler selects the registers to use to represent the input operands, it does not use any of the clobbered registers

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

关于c++ - 试图理解来自 g++ 的简单反汇编代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41891834/

相关文章:

c - GCC优化对线程并发的影响

c# - 我如何在字符串变量中运行 ASM 操作码或将其转换为字节?

c - 如何在不使用BIOS的情况下将数据写入显卡?

assembly - "DS:[40207A]"在汇编中是什么意思?

c++ - 一段C++代码得到 "invalid pointer"错误

python - 如何在c中扩展python?

不透明数据类型的 C++ 属性

linux - linux 和 windows 中的不同内存分配?

c++ - 将 remove_if 与 C 空终止字符串一起使用

c++ - 如何使用 std::thread C++ 生成调用相同函数的多个线程