繁体   English   中英

为什么 strlen 的这个 REPNE SCASB 实现有效?

[英]Why does this REPNE SCASB implementation of strlen work?

为什么这段代码有效?

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主:

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

64 位 sysv 调用约定将第一个参数放入rdi 所以调用者main已经为你做了那个负载。 您可以检查其汇编代码并亲自查看。

(答案由小丑提供)

问题中的代码是 strlen 的 32 位版本,它仅部分地在 64b 环境中工作,有点“偶然”(因为大多数 SW 在现实中都可以工作,无论如何 ;) )。

64b 环境的一个意外影响是(在 System V ABI 中,64b linux 操作系统使用,其他 64b 平台可能遵循不同的调用约定,使此无效!),函数调用中的第一个参数通过rdi寄存器传递,并且scasb在 64b 模式下使用es:rdi ,所以这很自然地结合在一起(正如 Jester 的回答所说)。

其余 64b 环境效果较差,该代码将返回 4+G 长字符串的错误值(我知道,在实际使用中极不可能发生,但可以通过提供如此长字符串的综合测试进行尝试)。

固定 64b 版本(也结束了例程利用 rax=0 在单个指令中同时执行neg ecxmov 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM