【发布时间】:2015-08-21 01:29:49
【问题描述】:
我有一个CpuFeatures 课程。类的要求很简单:(1)保留EBX或RBX,(2)将CPUID返回的值记录在EAX/EBX/ECX/EDX中。我不确定生成的代码是不是我想要的代码。
CpuFeatures 类代码使用 GCC 扩展 ASM。以下是相关代码:
struct CPUIDinfo
{
word32 EAX;
word32 EBX;
word32 ECX;
word32 EDX;
};
bool CpuId(word32 func, word32 subfunc, CPUIDinfo& info)
{
uintptr_t scratch;
__asm__ __volatile__ (
".att_syntax \n"
#if defined(__x86_64__)
"\t xchgq %%rbx, %q1 \n"
#else
"\t xchgl %%ebx, %k1 \n"
#endif
"\t cpuid \n"
#if defined(__x86_64__)
"\t xchgq %%rbx, %q1 \n"
#else
"\t xchgl %%ebx, %k1 \n"
#endif
: "=a"(info.EAX), "=&r"(scratch), "=c"(info.ECX), "=d"(info.EDX)
: "a"(func), "c"(subfunc)
);
if(func == 0)
return !!info.EAX;
return true;
}
下面的代码是在 Cygwin i386 上使用 -g3 -Og 编译的。当我在调试器下检查它时,我不喜欢我所看到的。
Dump of assembler code for function CpuFeatures::DoDetectX86Features():
...
0x0048f355 <+1>: sub $0x48,%esp
=> 0x0048f358 <+4>: mov $0x0,%ecx
0x0048f35d <+9>: mov %ecx,%eax
0x0048f35f <+11>: xchg %ebx,%ebx
0x0048f361 <+13>: cpuid
0x0048f363 <+15>: xchg %ebx,%ebx
0x0048f365 <+17>: mov %eax,0x10(%esp)
0x0048f369 <+21>: mov %ecx,0x18(%esp)
0x0048f36d <+25>: mov %edx,0x1c(%esp)
0x0048f371 <+29>: mov %ebx,0x14(%esp)
0x0048f375 <+33>: test %eax,%eax
...
我不喜欢我所看到的,因为 EBX/RBX 似乎没有被保留(xchg %ebx,%ebx+11)。此外,看起来保留的EBX/RBX 被保存为CPUID 的结果,而不是CPUID 返回的EBX 的实际值(xchg %ebx,%ebx 在+15,在mov %ebx,0x14(%esp) 之前+29)。
如果我将操作数更改为使用带有"=&m"(scratch) 的内存操作,那么生成的代码是:
0x0048f35e <+10>: xchg %ebx,0x40(%esp)
0x0048f362 <+14>: cpuid
0x0048f364 <+16>: xchg %ebx,0x40(%esp)
一个相关的问题是What ensures reads/writes of operands occurs at desired times with extended ASM?
我做错了什么(除了在本应花费 5 或 15 分钟的事情上浪费了无数小时)?
【问题讨论】:
-
您可能错过了我对我们讨论的最后一个问题所做的评论。您可能会考虑使用特定的寄存器,例如
"=D"而不是=&r。然而,关于%ebx的重用——这只是一个问题,如果%ebx需要 被保留。我注意到您没有使用-fPIC进行编译,这表明编译器可以免费使用ebx。如果你用-fPIC编译会发生什么? -
我的猜测是
-fPIC不应该使用ebx,接下来可能会选择%esi(或其他可用寄存器)。 -
还应该指出,即使使用
-fPIC生成 x86_64 也可能不是问题,因为 PIC 代码的使用还取决于所使用的内存模型(和 ABI)。%rbx可能不需要保留(在这些情况下,PIC 的处理方式不同)。这个article对X86_64上PIC的合理解释 -
@MichaelPetch - 在 Cygwin 上使用
-fPIC编译会得到 -fPIC ignored for target (all code is position independent), useless warning 和 Why does Cygwin's GCC display the first line of every file?。 -
@MichaelPetch - "...x86_64 即使使用 -fPIC 也可能不是问题" - 这就是问题所在。它可能需要(也可能不需要)。对我们来说,在所有情况下都更容易保存它以避免任何问题和未来(或过去)的问题。对我们来说,过去可以追溯到 1990 年代,因此我们需要确保我们不会破坏级别(旧)客户。