strchr()函数实现的问题

C.E*_*iss 1 unix assembly x86-64

我最近开始研究汇编代码,我正在尝试重新编码一些基本的系统函数来掌握它,我目前仍然在我的0x0上遇到了一个分段错误strchr.

section .text
global strchr

strchr:
    xor rax, rax

loop:
    cmp BYTE [rdi + rax], 0
    jz end

    cmp sil, 0
    jz end

    cmp BYTE [rdi + rax], sil
    jz good

    inc rax
    jmp loop

good:
    mov rax, [rdi + rcx]
    ret

end:
    mov rax, 0
    ret
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚如何使用GDB调试它,我遇到的文档非常有限或难以理解.

我在C中使用以下主要测试

extern char *strchr(const char *s, int c);

int main () {
   const char str[] = "random.string";
   const char ch = '.';
   char *ret;

   ret = strchr(str, ch);
   printf("%s\n", ret);
   printf("String after |%c| is - |%s|\n", ch, ret);

   return(0);
}
Run Code Online (Sandbox Code Playgroud)

眠りネ*_*ネロク 5

问题

紧跟good标签后的说明:

mov rax, [rdi + rcx]
Run Code Online (Sandbox Code Playgroud)

应该是:

lea rax, [rdi + rax]
Run Code Online (Sandbox Code Playgroud)

你完全没有使用rcx,但是rax,你需要的是那个位置的地址,而不是那个位置的值(即lea代替mov).


一些忠告

  1. 请注意,与零进行比较sil的典型习惯用法实际上是test sil, sil代替cmp sil, 0.那就是:

    test sil, sil
    jz end
    
    Run Code Online (Sandbox Code Playgroud)

    但是,如果我们查看strchr(3)手册页,我们可以找到以下内容:

    char *strchr(const char *s, int c);

    终止空字节被认为是字符串的一部分,因此如果c指定为' \0',则这些函数返回指向终结符的指针.

    因此,如果我们希望此strchr()实现的行为与手册页中所述相同,则必须删除以下代码:

    cmp sil, 0
    jz end 
    
    Run Code Online (Sandbox Code Playgroud)
  2. 典型的归零成语rax寄存器既不是mov rax, 0也不是xor rax, rax,而是xor eax, eax因为它没有编码的直接零和节省一个字节对于后者.


通过上述更正和建议,代码如下所示:

section .text
global strchr

strchr:
    xor eax, eax

loop:
    ; Is end of string?
    cmp BYTE [rdi + rax], 0
    jz end

    ; Is matched? 
    cmp BYTE [rdi + rax], sil
    jz good

    inc rax
    jmp loop

good:
    lea rax, [rdi + rax]
    ret

end:
    xor eax, eax
    ret
Run Code Online (Sandbox Code Playgroud)

  • 我认为`test sil,sil` /`jz end`应该完全删除,而不仅仅是从循环中提升.`strchr(string,0)`应该像strlen一样工作,而不是返回not-found.[`strchr(3)`手册页](http://man7.org/linux/man-pages/man3/strchr.3.html)甚至提到了这种情况:`如果c被指定为'\ 0',这些函数返回一个指向终结符的指针 (2认同)