试图理解来自 g++ 的简单反汇编代码
Trying to understand simple disassembled code from g++
我仍在努力使用 g++ 内联汇编程序并试图了解如何使用它。
我从这里改编了一段代码:http://asm.sourceforge.net/articles/linasm.html(引用自 gcc 信息文件中的 "Assembler Instructions with C Expressions Operands" 部分)
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 [=12=]x1,-0xc(%rbp) ;initialize foo
0x00000000000009e9 <+11>: movl [=12=]x2,-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() 函数 returns 错误的值。
有什么想法吗?到底是怎么回事?如何正确处理?
-- 编辑 --
根据@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;
}
我一直在关注的教程似乎具有误导性。 output/input字段中的"eax"并不是指寄存器本身,而是缩写table上的e,a,x缩写。
反正我还是没看懂。上面的代码导致编译错误:'asm' operand has impossible constraints.
我不明白为什么。
x86 的扩展内联汇编约束在 official documentation 中列出。
complete documentation 也值得一读。
如你所见,约束都是单个字母。
约束 "eax" fo foo
指定三个约束:
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".
您需要从 clobbers 中删除 eax
(顺便说一句,由于高位归零,它应该是 rax
)(并添加 "cc")。
我仍在努力使用 g++ 内联汇编程序并试图了解如何使用它。
我从这里改编了一段代码:http://asm.sourceforge.net/articles/linasm.html(引用自 gcc 信息文件中的 "Assembler Instructions with C Expressions Operands" 部分)
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 [=12=]x1,-0xc(%rbp) ;initialize foo
0x00000000000009e9 <+11>: movl [=12=]x2,-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() 函数 returns 错误的值。
有什么想法吗?到底是怎么回事?如何正确处理?
-- 编辑 -- 根据@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;
}
我一直在关注的教程似乎具有误导性。 output/input字段中的"eax"并不是指寄存器本身,而是缩写table上的e,a,x缩写。
反正我还是没看懂。上面的代码导致编译错误:'asm' operand has impossible constraints.
我不明白为什么。
x86 的扩展内联汇编约束在 official documentation 中列出。
complete documentation 也值得一读。
如你所见,约束都是单个字母。
约束 "eax" fo foo
指定三个约束:
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".
您需要从 clobbers 中删除 eax
(顺便说一句,由于高位归零,它应该是 rax
)(并添加 "cc")。