Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在linux上的程序集64中实现strcmp函数_C_Linux_Assembly_Nasm_Strcmp - Fatal编程技术网

在linux上的程序集64中实现strcmp函数

在linux上的程序集64中实现strcmp函数,c,linux,assembly,nasm,strcmp,C,Linux,Assembly,Nasm,Strcmp,我正在尝试实现assembly 64中的C函数,以下是我目前的工作代码: global ft_strcmp section .text ft_strcmp: ;rax ft_strcmp(rdi, rsi) mov r12, 0 loop: mov r13b, [rdi + r12] cmp byte [rdi + r12], 0 jz exit cmp byte [rsi

我正在尝试实现assembly 64中的
C
函数,以下是我目前的工作代码:

global ft_strcmp

section .text

ft_strcmp:              ;rax ft_strcmp(rdi, rsi)
        mov     r12, 0  
loop:
        mov r13b, [rdi + r12]
        cmp byte [rdi + r12], 0
        jz exit
        cmp byte [rsi + r12], 0
        jz exit
        cmp r13b, byte [rsi + r12]
        jnz  exit
        inc r12
        jmp loop

exit:
        sub r13b, [rsi + r12]
        movsx rax, r13b
        ret 
当我试图用这个
main.c
编译它时:

#include <stdio.h>
#include <string.h>

int     ft_strcmp(const char *str1, const char *str2);

int     main()
{
        const char      str1[20] = "hella world";
        const char      str2[20] = "hello world";

        printf("ft_strcmp = %d\n",ft_strcmp(str1, str2));
        printf("strcmp = %d\n",strcmp(str1, str2));
   
        return (0);
}
这是从
a
中减去
o
的结果:
ret='a'-'o'
是十进制ascii码
97-111=-14

但当我用另一个
main.c
尝试它时,我只是直接将字符串传递给
strcmp()
ft\u strcmp()
,而不是传递声明的变量:

#include <stdio.h>
#include <string.h>

int     ft_strcmp(const char *str1, const char *str2);

int     main()
{
        printf("ft_strcmp = %d\n",ft_strcmp("hella world", "hello world"));
        printf("strcmp = %d\n",strcmp("hella world", "hello world"));
        return (0);
}
我在互联网上搜索了一下,找到了一些关于这种行为的解释:

但问题是我如何在我的汇编代码中实现这种行为,我的意思是有没有办法知道字符串是否直接传递给参数

我试着用
lldb
调试一下,发现
rdi
rsi
的地址(分别获取第一个参数和第二个参数的寄存器)
在上述两种情况下是不同的

在第一种情况下,地址是这样写的:

rdi = 0x00007fffffffde50  ; the address of the first string
rsi = 0x00007fffffffde70  ; the address of the second string
但在第二种情况下,它们是这样写的:

rdi = 0x0000555555556010  ; the address of the first string
rsi = 0x0000555555556004  ; the address of the second string
rdi = 0x0000555555556010  ; the address of the first string
rsi = 0x0000555555556004  ; the address of the second string
rdi = 0x00007fffffffde50  ; the address of the first string
rsi = 0x00007fffffffde70  ; the address of the second string
我不确定这是否会有帮助,但谁知道呢,请提前感谢

#编辑

既然我的问题标记为[重复],我将发布我的答案,它似乎完成了上述行为的工作,如下所示:

使用
lldb
进行调试后,我注意到每当我向
ft_strcmp()
传递文本字符串时,
rdi
rsi
的地址都是这样写的:

rdi = 0x0000555555556010  ; the address of the first string
rsi = 0x0000555555556004  ; the address of the second string
rdi = 0x0000555555556010  ; the address of the first string
rsi = 0x0000555555556004  ; the address of the second string
rdi = 0x00007fffffffde50  ; the address of the first string
rsi = 0x00007fffffffde70  ; the address of the second string
每当我传递声明的变量而不是文字字符串时,地址就会变成这样:

rdi = 0x0000555555556010  ; the address of the first string
rsi = 0x0000555555556004  ; the address of the second string
rdi = 0x0000555555556010  ; the address of the first string
rsi = 0x0000555555556004  ; the address of the second string
rdi = 0x00007fffffffde50  ; the address of the first string
rsi = 0x00007fffffffde70  ; the address of the second string
“至少这是我在使用linux X64操作系统的机器上得到的”,所以我考虑做一些转移技巧:

这就是
0x00007fffffffde50
以二进制表示的方式:

 11111111111111111111111111111111101111001010000
为了得到
7
以便稍后在比较中使用它,我将它移位44位,在本例中,让我们将它存储在
rax
寄存器中:

mov rax, 0x00007fffffffde50
rax >> 44  in assembly ==> shr  rax, 44 ==> (rax = 111 ==> 7)
现在我将检查
rdi
rsi
是否为文字字符串:

mov r8, rdi       ; store the address of rdi in r8
shr r8, 44        ; right shift the address of r8 by 44 bits
cmp r8, rax       ; compare if the results are the same or not
jl  loop2         ; if r8 < rax then jump to loop2 for example 5 < 7
现在,当我使用上面的
main.c
编译时,结果是相同的。

strcmp()
只保证结果的符号。在第二种情况下,某些东西可能得到了优化。你不必在意大小的不同,所以最好不要在意

编译器有权进行优化

printf("strcmp = %d\n",strcmp("hella world", "hello world"));


这听起来像是一个错误。为什么你认为你需要这种精确的行为?天哪,你测试并调试了它!这太罕见了,我的咖啡杯掉了。请对此进行投票:)注意,字节减法后的
movsx-rax,r13b
并非适用于所有情况。在进行减法运算之前,需要对输入进行零扩展,以使有符号溢出成为不可能。出于同样的原因,
jg
不仅检查SF,还检查SF和OF。如果调用了glibc函数,编译器不会内联
strcmp
,也不会在编译时评估结果。是一个潜在的复制品。如果您想阻止gcc内联
strcmp
,请使用
gcc-fno builtin strcmp
。您正在根据它们的地址检测堆栈上的局部变量与静态存储。这是非常脆弱的,并不总是与编译器匹配。e、 g.您可以拥有不在堆栈上的非常量字符串!!例如
charstr1[]=“foo”在全局范围内。如果您想了解GCC版本中发生了什么,您应该看看它的asm。你所发明的与结果相匹配的方法是疯狂的,这是你在现实生活中永远不想做的事情,而且只是碰巧在这种情况下给出了正确的结果,而不是在一般情况下。