nasm x86_64 中的 strcmp 寄存器

Strcmp in nasm x86_64, registers

我正在尝试在 asm 中实现我自己的 strcmp。这是 ft_strcmp.s 文件:

global ft_strcmp

section .text
ft_strcmp:
            mov eax, [rdi]
            sub eax, [rsi]
            jne .exit
            cmp byte [rdi], 0 ; if s1 end
            je .exit
            cmp byte [rsi], 0 ; if s2 end
            je .exit
            inc rdi
            inc rsi
            jmp ft_strcmp
.exit:
            ret

第一个字母没问题: char *s1 = "你好世界" char *s2 = "Jdllo 世界" 结果为 1。 (0000 0001)

问题是当我尝试比较这些字符串时:

char *s1 = "Hello World"

char *s2 = "Hdllo 世界"

RAX 中的结果不是 1,而是 256。(0000 0001 0000 0000)

另一个例子:

char *s1 = "Hello World"

char *s2 = "Hcllo 世界"

RAX 中的结果不是 2,而是 512。(0000 0010 0000 0000)

如您所知,第三个不同字母的结果将是:

char *s1 = "Hello World"

char *s2 = "Heklo World"

RAX 中的结果不是 1,而是 65 536。(0000 0001 0000 0000 0000 0000)

我意识到RAX递增不对,但我找不到代码中的错误。 所以我请你帮我理解。

汇编与其他语言不同,所以很多时候您认为可能正在发生的事情实际上并非如此。您得到令人惊讶/不正确结果的原因是因为您减去两个数字。在获得调试器之前,您不会立即看到这一点(如果您想在汇编中学习/生存,则应该已经拥有)。让我们看看在调试器的帮助下发生了什么。 首先让我们设置一个小 main 和一些数据:

section .data
    str1: db "Hello world",0
    str2: db "Hdllo world",0

section .text
global main

ft_strcmp:
... ; your code here

main:
   nop
   mov rdi, str1
   mov rsi, str2
   
   call ft_strcmp
   nop

当执行开始时,我们加载 rdirsi 字符串(这只是一个字节序列)。这里重要的是 rdirsi 实际上并不“包含”字符串/字节,而是指向它们,即 rdirsi 包含位置的地址我们的琴弦所在的地方。

接下来我们调用该函数,这就是问题开始发生的地方。我将重点关注这两个说明:

    mov eax, [rdi] ;1
    sub eax, [rsi] ;2

在指令 1 中,您正在将字符串本身移动到 eax 中。 [rdi]表示得到rdi的地址的值。这就像取消引用指针。现在,eax 的大小为 32 位(4 个字节),因此它只能包含 4 个字节。假设你有一个 litte endian 系统,字节的顺序将是相反的,所以 eax 中的值将是:

eax = 0x6c6c6548

如果你仔细看,你会发现它是 str1:

的 4 个字节
6c  6c   65  48
'l' 'l' 'e'  'h'

接下来从 rsi 中地址的值中减去这个数字,即:

0x6c6c6448
OR
0x6c 6c  64  48
'l' 'l' 'd'  'h'

如果减去这两个数字:

0x6c6c6548 - 0x6c6c6448 = 0x100

0x100 以 10 为基数是 256。

由于该值不为零,因此不会设置 ZF(零标志),您将跳转到 .exit

希望你现在明白实际发生了什么。

我强烈建议获取调试器并使用它来调试此类问题。