尝试在x86 GAS中实现strlen

尝试在x86 GAS中实现strlen,x86,x86-64,gnu-assembler,X86,X86 64,Gnu Assembler,所以我对汇编编程非常陌生,我正在尝试编写一个可以计算字符串长度的函数 我觉得我在清除寄存器中的值或指针的增量方面有一些问题,因为返回的值对我来说总是“4571+length” 基本上,如果字符串长度为0,则返回值为4571。 如果字符串长度为6,则返回值为4577,以此类推 这是我的代码,任何帮助都将不胜感激: .globl my_strlen my_strlen: pushq %rbp movq %rsp, %rbp pushq %r12

所以我对汇编编程非常陌生,我正在尝试编写一个可以计算字符串长度的函数

我觉得我在清除寄存器中的值或指针的增量方面有一些问题,因为返回的值对我来说总是“4571+length”

基本上,如果字符串长度为0,则返回值为4571。 如果字符串长度为6,则返回值为4577,以此类推

这是我的代码,任何帮助都将不胜感激:

.globl my_strlen
    my_strlen:
        pushq %rbp
        movq %rsp, %rbp
        pushq %r12
        pushq %r13

        movq $0, %rax
        cmp $0, (%rdi)
        jne my_strlen_loop
        ret

    my_strlen_loop:
        inc %rax
        inc %rdi
        cmp $0, (%rdi)
        jne my_strlen_loop

        popq %r13
        popq %r12
        popq %rbp
        ret

这段代码有两个问题

首先,
cmp
指令没有指定大小,而且两个操作数都不是寄存器,因此不明确。对于大多数指令(如
mov$0,(%rdi)
),GAS会拒绝将其组装,但
cmp
出于某种原因,会将其组装为
cmpl
,比较dword。明确地将助记符更改为
cmpb


第二,在第一次ret之前,它不会弹出被按下的寄存器。最好跳到末尾(并进行一次ret)。

此代码有两个问题

首先,
cmp
指令没有指定大小,而且两个操作数都不是寄存器,因此不明确。对于大多数指令(如
mov$0,(%rdi)
),GAS会拒绝将其组装,但
cmp
出于某种原因,会将其组装为
cmpl
,比较dword。明确地将助记符更改为
cmpb


第二,在第一次ret之前,它不会弹出被按下的寄存器。最好跳到末尾(并进行一次ret)。

在“ret”之前添加以下内容:“sub$4571,%rax”,这更像是一个临时修复。为什么4571首先要进入rax?是的,这是个玩笑。:-)我正在写一个真实的答案。除了RAX和RDI,你不需要对寄存器做任何事情。让R12和R13单独呆着。另外,RBP,您不需要遗留堆栈框架。这只是作为框架代码的一部分提供给我们的。我知道我不需要这三个寄存器,但我只是保留了它,在“ret”之前添加它:“sub$4571,%rax”,这更像是一个临时修复。为什么4571首先要进入rax?是的,这是个玩笑。:-)我正在写一个真实的答案。除了RAX和RDI,你不需要对寄存器做任何事情。让R12和R13单独呆着。另外,RBP,您不需要遗留堆栈框架。这只是作为框架代码的一部分提供给我们的。我知道我不需要这三个寄存器,但我只是保留了它。它返回4571的原因很简单,因为这是程序数据中的第一个位置,它找到了4个连续的0字节,所以cmp匹配。它没有拒绝组装它。将“cmp”更改为“cmpb”成功了!非常感谢,我添加了一个标签来进行弹出和返回。再次感谢。@Suhas和prl:我错了,我以为我知道GAS会在那里做什么,但由于某种原因,
cmp
不同于
mov$0,(%rdi)
,并且会组装到dword
cmp
。我认为这是一个错误,没有错误,并组装至少没有警告。我同意,这似乎是一个错误的气体。它返回4571的原因仅仅是因为这是第一个地方,在您的程序的数据,它发现4个连续0个字节,使CMP匹配。它不拒绝组装它。将“cmp”更改为“cmpb”成功了!非常感谢,我添加了一个标签来进行弹出和返回。再次感谢。@Suhas和prl:我错了,我以为我知道GAS会在那里做什么,但由于某种原因,
cmp
不同于
mov$0,(%rdi)
,并且会组装到dword
cmp
。我认为这是一个错误,没有错误,并组装,至少没有警告。我同意,这似乎是一个错误的气体。