为什么报告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