我正在尝试在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=";Hello World"char*s2=";Jdllo World";结果是1。(0000 0001(
问题是,当我试图比较这些字符串时:
char*s1=";Hello World">
char*s2=";Hdllo World";
RAX中的结果不是1,而是256。(0000 00010000 0000(
另一个例子:
char*s1=";Hello World">
char*s2=";Hcllo World">
RAX中的结果不是2,而是512。(0000 00100000 0000(
正如你已经理解的,第三个不同字母的结果将是:
char*s1=";Hello World">
char*s2=";赫克洛世界;
RAX中的结果不是1,而是65536。(0000 00010000 0000 0000(
我意识到RAX的递增是不对的,但我在代码中找不到错误。所以我请你帮我理解。
Assembly与其他语言不同,因此您认为可能发生的事情往往并不是实际发生的事情。你得到令人惊讶/不正确结果的原因是你减去了两个数字。在获得调试器(如果您想在程序集中学习/生存,则应该已经拥有调试器(之前,您不会立即看到这一点。让我们看看在调试器的帮助下发生了什么。首先,让我们设置一个小型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
当执行开始时,我们用字符串(这只是一个字节序列(加载rdi
和rsi
。这里重要的是CCD_ 4和CCD_;包含";但指向它们的字符串/字节(即rdi
和rsi
(包含我们的字符串所在位置的地址。
接下来我们调用这个函数,这里是问题开始发生的地方。我将重点介绍这两条指令:
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
基站10中的CCD_ 16是256。
由于该值不是零,因此不会设置ZF
(零标志(,您将跳转到.exit
。
希望你现在了解实际发生了什么。
我强烈建议您使用调试器来调试此类问题。