c - 汇编:在函数中访问同一个寄存器的四字、双字、字节数

标签 c assembly x86-64

我有一些从 C 生成的汇编代码,我正在尝试理解这些代码。有一部分我无法理解:

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

没有意义的是%rcx%ecx%cl都在同一个寄存器中(四字、双字和字节)。一个数据类型怎么能像这样在同一个函数中访问所有三个?

拥有一个 char* 使得以这种方式访问​​ %ecx 变得不可能,同样拥有一个 int* 使得访问 %cl 不太可能。我根本不知道什么数据类型可以存储在 %rcx 中。

最佳答案

回复:您的评论:您可以看出它是一个字节数组,因为它将 %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上对之前的内容产生错误的依赖。只有 Intel P6/SnB 系列 CPU 单独跟踪整数寄存器的片段(并插入一个额外的 uop 以将它们与旧内容合并,如果你在写 %cl.)

因此,对于编译器来说,使用零扩展 movzbl 加载发出该代码是完全合理的,而不仅仅是 mov (%rdi,%rcx,1), %cl。它可能会在 Silvermont 和 AMD 上运行得更快。 (还有 P4。针对旧 CPU 的优化确实存在于编译器源代码中……)

关于c - 汇编:在函数中访问同一个寄存器的四字、双字、字节数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33250030/

相关文章:

c++ - 循环链表的循环起始节点

c - 结构指针错误

c - x86_64 内联汇编中 %c 有什么用?

c - 字符串数组的段错误

c - 为单元测试编写复杂的预处理器宏

assembly - MIPS 中的回文生成

c - 将一个字节数组与许多其他字节数组进行比较的最快方法?

assembly - 常量非不变 tsc 可以跨 cpu 状态改变频率吗?

linux-kernel - linux 虚拟内存用户/内核空间在 x86_64 中拆分

linux - 在汇编中调用printf时如何设置颜色