汇编:在函数中访问相同寄存器的四字,双字和字节数

时间:2015-10-21 02:37:10

标签: c assembly x86-64

我有一些从C生成的汇编代码,我正试图弄清楚。我无法理解的一部分:

movslq   %edx,%rcx
movzbl   (%rdi,%rcx,1),%ecx
test     %cl,%cl

没有意义的是%rcx%ecx%cl都在同一个寄存器中(分别为四字,双字和字节)。数据类型如何在同一个函数中访问这三个?

拥有char*会以不可思议的方式访问%ecx,同样拥有int*也无法访问%cl。我根本不知道%rcx中可以存储哪种数据类型。

1 个答案:

答案 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的优化确实在编译器源代码中徘徊......)