C语言 如何让GCC知道EFLAGS寄存器中的方向标志DF在内联asm中发生了变化?



例如,以下代码:

void ppp(void);
void kkk()
{
__asm__ volatile("std":::"cc");
ppp();
}

在调用ppp()之前,由于x86 API,需要执行cld。参考x86程序执行时方向标志(DF)的默认状态

但是,程序集出来了:

.globl  kkk
.type   kkk, @function
kkk:
#APP
# 5 "test.c" 1
std
# 0 "" 2
#NO_APP
jmp     ppp@PLT
.size   kkk, .-kkk

根据GCC文档(https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html), "表示x86_64中的EFLAGS寄存器。为什么GCC不执行cld?

正如您已经了解的那样,i386 ABI(和AMD64 System V ABI)要求方向标志(DF)是明确的,以便为依赖该标志的指令启用前向。字符串指令)。

x86/x86-64上的FLAGS/EFLAGS/RFLAGS寄存器包含许多条件标志,但它也包含系统标志(如方向标志)。注意:在x87 FPU状态字中也有条件标志。

虽然内联汇编具有ccclober,但目前并非在所有目标cpu上使用。所有针对x86/x86-64处理器的GCC编译器上的asm语句都有一个隐含的ccclobber,并且该clobber具有无效.

GCC文档对于x86/x86-64目标的条件标志是什么有一点模糊。我相信可以从x86/x86-64目标的6.47.2.4标志输出操作数一节中的这句话推断出意图:

x86系列的标志输出约束如下所示' =@cccond ',其中cond是标准条件之一jcc或setcc的ISA手册.

特别是引用Jcc或SETcc支持的条件标志的最后一句话给了我们一个线索,告诉我们在x86/x86-64上内联汇编假定不保留哪些标志:进位标志(CF),溢出标志(OF),奇偶标志(PF),符号标志(SF)和零标志(ZF)。

注意:FLAGS寄存器中的一个标志,GCC根本不关心的是辅助标志(AF),它可以在处理某些指令时使用,如AAA


要真正回答方向标志(DF)问题,GCC不考虑flags/EFLAGS/RFLAGS寄存器中的大多数标志作为条件标志。像方向标志,陷阱标志,中断标志这样的东西并不适用。方向标志是一个奇怪的人,因为它是ABI中定义状态的唯一标志。

使用STD指令或其他方法在内联汇编asm语句中设置方向标志(向后处理)而不恢复它将是未定义的行为。如果在内联程序集asm语句中更改了方向标志,则有责任在相同的asm语句中恢复它。必须在控制从内联程序集返回之前恢复。

最新更新