为什么这个代码有效?
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 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

关于c - 为什么执行这种出色的工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42655541/

10-12 04:56