【发布时间】:2016-06-30 03:21:05
【问题描述】:
我是汇编新手(Intel x86_64),我正在尝试重新编码 C 库中的一些函数。我在 64 位 Linux 上使用 NASM 进行编译。
我的 strchr 函数出现错误,我找不到解决方案...
提醒一下,这里是 strchr 手册页的摘录:
char *strchr(const char *s, int c);
strchr() 函数返回一个指针,指向字符串 s 中字符 c 的第一次出现。
这是我尝试过的:
strchr:
push rpb
mov rbp, rsp
mov r12, rdi ; get first argument
mov r13, rsi ; get second argument
call strchr_loop
strchr_loop:
cmp [r12], r13 ; **DON'T WORK !** check if current character is equal to character given in parameter...
je strchr_end ; go to end
cmp [r12], 0h ; test end of string
je strchr_end ; go to end
inc r12 ; move to next character of the string
jmp strchr_loop ; loop
strchr_end
mov rax, r12 ; set function return
mov rsp, rbp
pop rbp
这会在字符串的 ned 上返回一个指针,但找不到字符...
我认为是这条线不起作用:
cmp [r12], r13
我对此进行了测试,并且成功了:
cmp [r12], 97 ; 97 = 'a' in ASCII
例子:
char *s;
s = strchr("blah", 'a');
printf("%s\n", s);
返回:
ah
但是我不能让它与寄存器比较一起工作。我做错了什么,我该如何解决?
【问题讨论】:
-
r13是一个 64 位寄存器。你的字符是一个字节。也许您打算使用r13b。 -
你需要保存和恢复你破坏的被调用者保存的寄存器。我知道的所有调用 x86-64 调用约定都要求保留
r12和r13。 -
获取有关 Linux 上 64 位代码调用约定的信息的最佳位置是查看 System V 64 位 ABI。特别是如果您想要调用者/被调用者寄存器列表及其用法,则可以在第 21 页的Figure 3.4 Register Usage 中找到它们。
-
对于不需要保存/恢复的暂存寄存器,首选使用 eax/ecx/edx,因为使用它们的指令不需要 REX 前缀。除了代码大小之外没有速度差异,但代码大小很重要。你可以增加
rsi;无需将其复制到另一个寄存器。请参阅x86 tag wiki,尤其是 Agner Fog 的指南。 -
调试器中的单步执行是必不可少的,顺便说一句。您是否尝试过,而不仅仅是查看返回值?
标签: linux assembly nasm x86-64