为什么用REPNE SCASB实施strlen工作? [英] Why does this REPNE SCASB implementation of strlen work?
问题描述
为什么此代码有效?
http://www.int80h.org/strlen/表示字符串地址具有进入EDI
寄存器以使scasb
正常工作,但是此汇编函数似乎没有执行此操作.
http://www.int80h.org/strlen/ says that the string address has to be in EDI
register for scasb
to work, but this assembly function doesn't seem to do this.
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主程序:
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
推荐答案
问题中的代码是32位版本的strlen,仅在64b环境中部分运行,有点偶然"(因为大多数SW都可以运行)实际上,无论如何;)).
The code from the question is 32 bit version of strlen, which works in 64b environment only partially, sort of "by accident" (as most of the SW works in reality, anyway ;) ).
64b环境的意外影响之一是(在64b linux操作系统使用的System V ABI中,其他64b平台可能遵循不同的调用约定,从而使此方法无效!),函数调用中的第一个参数被传递了rdi
寄存器,并且scasb
在64b模式下使用es:rdi
,因此这很自然地适合在一起(正如Jester的回答所说).
One of the accidental effects of 64b environment is (in System V ABI, which is used by 64b linux OS, other 64b platforms may follow different calling convention, invalidating this!), that the first argument in function call is passed through rdi
register, and the scasb
is using es:rdi
in 64b mode, so this naturally fits together (as the Jester's answer says).
在64b环境中,其余的效果不太好,代码将为4 + G长字符串返回错误的值(我知道,在实际使用中极不可能发生这种情况,但是可以通过提供这种长字符串的综合测试来尝试).
Rest of the 64b environment effects are less good, that code will return wrong value for 4+G long string (I know, highly unlikely to happen in practical usage, but can be tried by synthetic test providing such long string).
修复了64b版本(例程的结尾也利用rax = 0在单个指令中同时执行了neg ecx
和mov eax,ecx
):
Fixed 64b version (also the end of routine exploits rax=0 to do both neg ecx
and mov eax,ecx
in single instruction):
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
这篇关于为什么用REPNE SCASB实施strlen工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!