我有一些从C生成的汇编代码,我正试图弄清楚。我无法理解的一部分:
movslq %edx,%rcx
movzbl (%rdi,%rcx,1),%ecx
test %cl,%cl
没有意义的是%rcx
,%ecx
和%cl
都在同一个寄存器中(分别为四字,双字和字节)。数据类型如何在同一个函数中访问这三个?
拥有char*
会以不可思议的方式访问%ecx
,同样拥有int*
也无法访问%cl
。我根本不知道%rcx
中可以存储哪种数据类型。
答案 0 :(得分:0)
re:你的评论:你可以告诉它是一个字节数组,因为它将%rcx
缩放为1.
int func(char *array /* rdi */, int pos /* ecx */)
{
if (array[pos]) ...;
// or maybe
int tmpi = array[pos];
char tmpc = tmpi;
if (tmpc) ...;
}
ecx必须在用作有效地址中的偏移量之前将符号扩展到64位。如果它是无符号的,则仍然需要进行零扩展(例如mov %ecx, %ecx
)。当寄存器中传递的参数小于64位时,ABI不保证寄存器的高32被归零或符号扩展。
通常,最好写入至少32b的寄存器,以避免对某些CPU上的先前内容的错误依赖。只有英特尔P6 / SnB系列CPU分别跟踪整数寄存器(如果在写%ecx
后执行类似读取%cl
的操作,则插入额外的uop以将它们与旧内容合并。)
因此,编译器使用零扩展movzbl
加载而不仅仅mov (%rdi,%rcx,1), %cl
发出该代码是完全合理的。它可能会在Silvermont和AMD上运行得更快。 (和P4。旧CPU的优化确实在编译器源代码中徘徊......)