为什么报告SCASB实施strlen有效?

为什么报告SCASB实施strlen有效?,c,assembly,x86-64,calling-convention,strlen,C,Assembly,X86 64,Calling Convention,Strlen,为什么这个代码可以工作 表示字符串地址必须在EDI寄存器中,才能使scasb正常工作,但此汇编函数似乎无法做到这一点 mystrlen的汇编代码: global mystrlen mystrlen: sub ecx, ecx not ecx sub al, al cld repne scasb neg e

为什么这个代码可以工作

表示字符串地址必须在
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
输出:

./a.out
echo $?
4

64位sysv调用约定将第一个参数放入
rdi
。因此调用者
main
已经为您加载了。您可以检查它的汇编代码并亲自查看

(答覆由以下人士提供)


64位sysv调用约定将第一个参数放入
rdi
。因此调用者
main
已经为您加载了。您可以检查它的汇编代码并亲自查看


(答案由提供)

问题中的代码是strlen的32位版本,它只在64b环境中部分工作,有点“偶然”(因为大多数软件实际上都工作;)

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

其余的64b环境效果不太好,代码将为4+G长字符串返回错误的值(我知道,在实际使用中不太可能发生,但可以通过提供这种长字符串的合成测试来尝试)

固定64b版本(也是例程的末尾利用rax=0在单个指令中执行
neg ecx
mov eax,ecx
):


问题中的代码是strlen的32位版本,它只在64b环境中部分工作,有点“偶然”(因为大多数软件实际上都工作)

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

其余的64b环境效果不太好,代码将为4+G长字符串返回错误的值(我知道,在实际使用中不太可能发生,但可以通过提供这种长字符串的合成测试来尝试)

固定64b版本(也是例程的末尾利用rax=0在单个指令中执行
neg ecx
mov eax,ecx
):


64位sysv调用约定将第一个参数放入
rdi
。因此调用者
main
已经为您加载了。您可以检查它的汇编代码并亲自查看。
cld
也是无意义的/冗余的。调用约定要求在函数项处清除方向标志。@R。。这是什么意思?我对ASM很陌生,我相信这是偶然的,源代码实际上是32b,搜索最多4G字符串长度(如果您提供5G长的字符串,它将返回不正确的答案)。归零
ecx
也将清除
rcx
,但
not ecx
失败(
dec rcx
更好),然后
ecx
的剩余反转也必须调整为
rcx
,并在
rax
中返回值@Ped7g您是对的,添加这个作为答案吗?64位sysv调用约定将第一个参数放入
rdi
。因此调用者
main
已经为您加载了。您可以检查它的汇编代码并亲自查看。
cld
也是无意义的/冗余的。调用约定要求在函数项处清除方向标志。@R。。这是什么意思?我对ASM很陌生,我相信这是偶然的,源代码实际上是32b,搜索最多4G字符串长度(如果您提供5G长的字符串,它将返回不正确的答案)。归零
ecx
也将清除
rcx
,但是
not ecx
是失败的(
dec rcx
会更好),然后
ecx
的剩余反转也必须调整为
rcx
,并在
rax
中返回值@Ped7g您是对的,添加这个作为答案吗?
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