GDC x86内联汇编:如何分配保留寄存器避免冲突?
GDC x86内联汇编中保留RBX并避免寄存器冲突的问题解答
1. 正确的实现方式
你当前的代码核心思路是正确的,关键在于**[save]的约束必须使用"=&r"(早期clobber寄存器)**:
=&r中的&标记会告诉编译器,这个寄存器会在输入寄存器被读取前就被修改,因此编译器不会将它分配给任何输入寄存器,或是需要保留到汇编代码后期的输出寄存器。- 你的逻辑流程没问题:用编译器分配的临时寄存器
%[save]先保存RBX原值,执行CPUID(会破坏RAX/RBX/RCX/RDX),再通过xchg恢复原RBX,同时把CPUID输出的RBX值转移到%[save]中作为结果返回。 - 需保持
"=a"/"=c"/"=d"的固定寄存器输出约束,既保证RAX/RCX/RDX的结果正确返回,也让编译器明确这三个寄存器会被CPUID修改,不会将它们分配给[save]。
2. 你的担心完全合理
如果去掉&早期clobber约束(比如只用"=r"),编译器可能出现致命问题:
- 把
[save]分配给RBX本身:此时mov %[save], rbx等价于空操作,完全没起到保存作用,CPUID破坏RBX后原数值丢失,且cpuid_rbx_out会得到错误的被破坏后的值。 - 把
[save]分配给RAX/RCX/RDX:这些寄存器会被CPUID覆盖,导致保存的原RBX值丢失,最终无法正确恢复RBX。
所以你的担心并非多余,早期clobber约束是确保代码可靠运行的必要条件。
3. 确保save寄存器与RBX/RAX/RCX/RDX不重复
通过以下两点即可保证:
- 使用
"=&r"早期clobber约束:编译器会自动避开输入寄存器,以及会在汇编中被修改的输出寄存器(这里RAX/RCX/RDX被明确指定为输出且会被CPUID修改)。 - 明确指定RAX/RCX/RDX为固定输出寄存器:编译器知道这三个寄存器会被CPUID覆盖,因此只会为
[save]分配RSI/RDI/R8-R15这类空闲寄存器,不会选中RBX/RAX/RCX/RDX。
不需要额外添加排除约束,当前写法已足够让编译器做出正确的寄存器分配。
4. 不需要定义未使用的额外输出
你的[save]是有用的输出寄存器,它负责返回CPUID输出的RBX值,并非冗余项。如果只是需要保存RBX但不需要返回该结果,才需要将RBX加入clobber列表,但这里你需要返回CPUID的RBX结果,所以把[save]作为输出是正确的选择,无需额外添加未使用的输出。
内容的提问来源于stack exchange,提问作者Cecil Ward
相关产品推荐
相关产品推荐

