为什么这段代码有效?
http://www.int80h.org/strlen/表示字符串地址必须位于EDI
为.....注册scasb
工作,但这个汇编功能似乎并没有做到这一点。
汇编代码为mystrlen
:
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 main:
int mystrlen(const char *);
int main()
{
return (mystrlen("1234"));
}
汇编:
nasm -f elf64 test.asm
gcc -c main.c
gcc main.o test.o
Output:
./a.out
echo $?
4
问题中的代码是 strlen 的 32 位版本,它仅部分地在 64b 环境中工作,有点“偶然”(因为大多数软件实际上都在现实中工作,无论如何;))。
64b 环境的一个意外影响是(在 64b linux 操作系统使用的 System V ABI 中,其他 64b 平台可能遵循不同的调用约定,从而使此无效!),函数调用中的第一个参数通过rdi
注册,并且scasb
正在使用es:rdi
在 64b 模式下,所以这自然适合在一起(正如小丑的回答所说)。
其余64b环境效果不太好,该代码将返回4+G长字符串的错误值(我知道,在实际使用中极不可能发生,但可以通过提供这么长字符串的综合测试来尝试)。
修复了 64b 版本(例程结束时还利用 rax=0 来执行这两项操作neg ecx
and 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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)