为什么用REPNE SCASB实施strlen工作? [英] Why does this REPNE SCASB implementation of strlen work?

查看:138
本文介绍了为什么用REPNE SCASB实施strlen工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么此代码有效?

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 ecxmov 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆