为什么这个代码有效?
http://www.int80h.org/strlen/表示字符串地址必须在EDI
寄存器中才能工作,但是这个汇编函数似乎没有做到这一点。scasb
的程序集代码:
global mystrlen
mystrlen:
sub ecx, ecx
not ecx
sub al, al
cld
repne scasb
neg ecx
dec ecx
dec ecx
mov eax, ecx
ret
C主要:
int mystrlen(const char *);
int main()
{
return (mystrlen("1234"));
}
编制:
nasm -f elf64 test.asm
gcc -c main.c
gcc main.o test.o
输出:
./a.out
echo $?
4
最佳答案
这个问题的代码是strlen的32位版本,它只在64b环境中部分工作,有点“偶然”(因为大多数软件实际上都工作;)。
64b环境的意外影响之一是(在64b linux操作系统使用的SystemV ABI中,其他64b平台可能会遵循不同的调用约定,从而使其失效!),函数调用中的第一个参数通过rdi
寄存器传递,而scasb
在64b模式下使用es:rdi
,所以这很自然地结合在一起(正如Jester的答案所说)。
剩下的64b环境效果不太好,该代码将返回4+G长字符串的错误值(我知道,在实际使用中极不可能发生,但可以通过提供这样长字符串的合成测试来尝试)。
修复了64b版本(也是在单个指令中利用rax=0同时执行neg ecx
和mov eax,ecx
的例程结束):
global mystrlen
mystrlen:
xor ecx,ecx ; rcx = 0
dec rcx ; rcx = -1 (0xFFFFFFFFFFFFFFFF)
; rcx = maximum length to scan
xor eax,eax ; rax = 0 (al = 0 value to scan for)
repne scasb ; scan the memory for AL
sub rax,rcx ; rax = 0 - rcx_leftover = scanned bytes + 1
sub rax,2 ; fix that into "string length" (-1 for '\0')
ret
关于c - 为什么执行这种出色的工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42655541/