gcc 如何知道内联汇编中使用的寄存器大小?
Posted
技术标签:
【中文标题】gcc 如何知道内联汇编中使用的寄存器大小?【英文标题】:How does gcc know the register size to use in inline assembly? 【发布时间】:2014-09-19 17:17:53 【问题描述】:我有内联汇编代码:
#define read_msr(index, buf) asm volatile ("rdmsr" : "=d"(buf[1]), "=a"(buf[0]) : "c"(index))
使用此宏的代码:
u32 buf[2];
read_msr(0x173, buf);
我发现反汇编是(使用 gnu 工具链):
mov eax,0x173
mov ecx,eax
rdmsr
mov DWORD PTR [rbp-0xc],edx
mov DWORD PTR [rbp-0x10],eax
问题是0x173小于0xffff,为什么gcc不使用mov cx, 0x173
? gcc会解析下面的指令rdmsr
吗? gcc 是否总是知道正确的寄存器大小?
【问题讨论】:
我相信是因为0x173
的类型是int
,所以gcc
使用了32位的mov
指令
mov cx, 0x173
不会将 ecx
设置为 0x173。高 16 位将包含早期计算中剩余的任何值。
@RaymondChen:我知道你说什么。我想知道为什么gcc知道必须使用“ecx”。
@RaymondChen 我相信问题是问 GCC 如何知道“c”约束是指 ecx
而不是 cx
或 rcx
。如果我是正确的,那么您的编辑会改变其含义。
【参考方案1】:
这取决于传递的值或变量的大小。
如果您传递一个“short int”,它将设置“cx”并从“ax”和“dx”读取数据(如果 buf 也是一个 short int)。
对于 char 它将访问 "cl" 等等。
所以“c”指的是“ecx”寄存器,但是根据访问的大小,可以使用“ecx”、“cx”或“cl”来访问,我认为这是有道理的。
为了测试你可以尝试通过(无符号短)0x173,它应该改变代码。
没有分析内联程序集(实际上是文本替换后直接复制到输出程序集,包括语法错误)。此外,没有默认寄存器大小,具体取决于您是 32 位还是 64 位目标。这将是一种限制方式。
【讨论】:
【参考方案2】:我认为答案是因为当前的默认数据大小是 32 位。在 64 位长模式下,默认数据大小也是 32 位,除非您使用“rex.w”前缀。
【讨论】:
不,C 中的0x173
具有类型 int
,它是 x86-64 System V ABI 中的 32 位类型。 这就是为什么它为"c"(0x173)
选择了一个 32 位寄存器。 int
的大小与默认操作数大小相同并非巧合,但它们是不同的东西。 (例如,gcc -m16
针对 16 位模式仍然使用 32 位 int 和指针,即使这要求汇编器在大多数指令上使用操作数大小和地址大小前缀。在非 x86 上,例如 AVR,@987654326 @ 需要 2 个寄存器。)【参考方案3】:
英特尔将 RDMSR 指令指定为使用(全部)ECX 来确定型号特定寄存器。在这种情况下,显然正如您的宏所指定的那样,GCC 完全有理由将您的常量加载到完整的 ECX 中。
所以关于为什么它不加载 CX 的问题似乎完全不合适。看起来 GCC 正在生成正确的代码。
(你没有问为什么它通过使用 EAX 来低效地分阶段 ECX 的负载;我不知道答案)。
【讨论】:
GCC 不能以这种方式工作。唯一决定分配哪个寄存器的是约束和类型的大小。 GCC 本身并不分析指令。即使它想也做不到,因为可能有不止一个指令。 如前所述,他的宏建立了对 ECX 的约束。就 GCC 确实 知道 RDMSR 的注册要求而言(它可能不知道,我不是 GCC 专家),所以如果 OP 以某种方式指定了 CX,RDMSR 代码生成器会反对它没有得到完整的价值。 如果您承认您不知道 GCC 是否以这种方式行事,为什么要在您的答案中写下它确实如此?正如我所说,GCC 不可能以这种方式运行,因为在内联汇编中rdmsr
之前可能还有其他指令,包括可能的分支指令,并且知道哪个指令是使用 ecx
的指令与解决停止问题一样困难问题。
如果只分配了cx
,代码生成器不会像您声称的那样给出错误:它只会使用高位的先前内容。
其明确的 OP 对出于 RDMSR 的目的设置 CX 感到困惑。很明显,他指定了“C”寄存器来设置该值。我不具体知道 GCC 代码生成器对指令做了什么,但它非常复杂,我可以想象(可能是错误的)它理解每条指令的输入和输出要求。虽然它可能无法确定一些自定义汇编代码是否正确设置了寄存器,但它有可能确定寄存器 ECX 是否未设置,因此如果只设置了 CX 可能会报错.以上是关于gcc 如何知道内联汇编中使用的寄存器大小?的主要内容,如果未能解决你的问题,请参考以下文章