我正在尝试使用从命令行参数获取输入的NASM来创建程序。由于没有提供字符串长度,我正在尝试创建一个计算我自己的函数。这是我的尝试,它获取指向ebx
寄存器中字符串的指针,并返回ecx
中字符串的长度:
len:
push ebx
mov ecx,0
dec ebx
count:
inc ecx
inc ebx
cmp ebx,0
jnz count
dec ecx
pop ebx
ret
我的方法是逐个字符地检查字符串,并检查它是否为空。如果不是,我递增ecx
并转到下一个字符。我认为问题是cmp ebx,0
对于我正在尝试做的事情是不正确的。我如何正确地检查字符是否为空?另外,还有其他我可以做得更好的事情吗?
答案 0 :(得分:4)
您正在将ebx
中的值与0进行比较,这不是您想要的。 ebx
中的值是内存中字符的地址,因此应该取消引用,如下所示:
cmp byte[ebx], 0
此外,最后push ebx
应为pop ebx
。
答案 1 :(得分:1)
以下是我在检查argv[1]
的64位Linux可执行文件中的操作方法。内核在堆栈上启动了一个argc
和argv[]
的新进程,如x86-64 System V ABI中所述。
_start:
pop rsi ; number of arguments (argc)
pop rsi ; argv[0] the command itself (or program name)
pop rsi ; rsi = argv[1], a pointer to a string
mov ecx, 0 ; counter
.repeat:
lodsb ; byte in AL
test al,al ; check if zero
jz .done ; if zero then we're done
inc ecx ; increment counter
jmp .repeat ; repeat until zero
.done:
; string is unchanged, ecx contains the length of the string
; unused, we look at command line args instead
section .rodata
asciiz: db "This is a string with 36 characters.", 0
这是缓慢而低效的,但很容易理解。
为了提高效率,你需要
movzx
而不是合并到之前的RAX值(Why doesn't GCC use partial registers?)来避免错误依赖。当然SSE2总是在x86-64中可用,所以我们应该使用它来检查16个字节的块(在到达对齐边界之后)。请参阅glibc中优化的手写strlen
实现。 (https://code.woboq.org/userspace/glibc/sysdeps/x86_64/strlen.S.html)。
答案 2 :(得分:0)
这是我如何编码的
len:
push ebx
mov eax, ebx
lp:
cmp byte [eax], 0
jz lpend
inc eax
jmp lp
lpend:
sub eax, ebx
pop ebx
ret
(结果在eax中)。可能有更好的方法。