【问题标题】:How to compare two registers in x86-64如何比较 x86-64 中的两个寄存器
【发布时间】:2019-04-12 15:57:19
【问题描述】:

我正在逐个字符比较汇编中的两个数组,C 代码将是这样的:

   count=0;
   for (i=0;i<vector;i++) {
     if (array1[i]==array2[i]) {
       count++;
     }
   }

基本上,两个数组都会进行比较,当该位置的字符相同时,计数会增加。

我最终在汇编中得到了这段代码,它实际上似乎按预期工作:

   forEachVector:
     cmp bl, vector
     jge endforEachVector
     mov rax, QWORD[array1+rbx] ; move array[i] to rax
     mov rdx, QWORD[array2+rbx] ; move array[i] to rdx

     if1Equals2:
     cmp dl, al
     jne fi1Equals2
     inc cl
     fi1Equals2:

     inc bl
     jmp forEachVector
   endforEachVector: 

vector 是一个常量,array1 和 2 是 extern,在 C 中定义为“char array1[vector]”。 据我了解,array1[i] 是 16 位长,因为它是一个 char 数组,而 char 是一个 int == 16 位。因此,首先我尝试使用完整的 64 位寄存器进行操作,就像:

cmp rdx, rax

如果我使用 64 位寄存器(未设置零位,因此触发 jne 并且如果结束),代码将失败,它仅在我使用 al 和 dl (8 lsb) 并且我想了解原因时才有效。

比较 8 lsb 没问题,因为 arrayX[i] 永远不会高于 2^8,但是做 cmp rax, rdx 和 cmp al, dl 应该有同样的效果。

【问题讨论】:

  • 好的,c 字符串存储 8 位值,而不是 16 位。宽数组或 UTF 或其他可能会有所不同,但标准 C 字符串是 8 位的,因此您的比较有效。
  • 这是一个确保我们相互理解的神器:godbolt.org/z/nvye_k

标签: assembly x86-64


【解决方案1】:

rax 是一个 qword 寄存器,8 字节 = 64 位。

char 是 8 位 = 1 字节,不是 16 位。 (而int 是 64 位 x86 编译器的 32 位类型。如果您好奇,请查看编译器生成的代码。)

如果一次加载 8 个字符并将整个 qword 寄存器与cmp rdx, rax 进行比较,它类似于memcmp(array1+i, array2+i, 8)(但实际上实现 memcmp 会使用 bswap,因为 x86 是little endian,但对于 memcmp,first 的区别很重要。)

您当前的代码有效,因为即使您加载 8 个字节,您也只查看低位单字节部分寄存器。

但是如果你给它一个指向页面中最后一个字符的指针,并且下一个内存页面没有映射,你的程序就会出错。您从最后一个字符的地址加载的 8 字节将跨入未映射的页面和段错误。

使用movzx eax, byte [rdi] 加载单个字节,零扩展至更宽的寄存器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    • 2011-11-04
    • 1970-01-01
    相关资源
    最近更新 更多