地址是在它之后还是之前执行?
问题描述:
对不起,我不知道该怎么问这个问题,但让我看看能不能把它画出来。我有这个程序:地址是在它之后还是之前执行?
section .data
s1 db "nice",10,0
section .text
global _start
_start:
mov rax, s1
call _print
call _exit
_print:
push rax
mov rbx, 0
_printLoop:
inc rax
inc rbx
mov cl, [rax]
cmp cl, 0
jne _printLoop
mov rax, 1
mov rdi, 1
pop rsi
mov rdx, rbx
syscall
ret
_exit:
mov rax, 60
mov rdi, 0
syscall
其中有一个子例程_print将打印一些空终止的字符串与地址存储在rax中。我的问题是,我假设,如果我有记忆的指针一些字符串(如S1),那么它会是这个样子:
rax
s1
|
[n][i][c][e][\n][\0]
所以,在我的脑海,我想检查存储在s1中以确保第一个字符(“nice”中的'n')不是空终止符。但这不是这个程序的工作原理。它增加兵营和RBX(RBX存储计)和S1 + 1首先检查,像这样:
s1 rax
| |
[n][i][c][e][\n][\0]
所以,我能想到的唯一解释,就是S1指针或者,在一开始,分在分配给字符串的字节之前,如下所示:
s1
|
[][n][i][c][e][\n][\0]
,或者当从中读取时,它向后读取,而不是向前读取。但我不确定它是如何工作的。我希望我已经足够清楚,有人为我解决这个问题。谢谢。这个x86-64
答
只要字符串至少有一个字符,写入的代码的长度就是正确的。 (这是一个合理的假设,因为打印没有字符的字符串会是什么意思,但不幸的是它不健壮。)
修复它以正确处理空字符串的一个简单方法是:
_print:
mov rsi, rax
mov rbx, 0
cmp byte [rax], 0
jz _printSkip
_printLoop:
inc rax
inc rbx
mov cl, [rax]
cmp cl, 0
jne _printLoop
mov rax, 1
mov rdi, 1
mov rdx, rbx
syscall
_printSkip:
ret
除了在循环之前为空字符串添加检查之外,我将其更改为将指针直接放入rsi而不是堆栈中。通过不使用堆栈来节省rax,它可以避免在跳过系统调用的情况下需要堆栈清理。
答
在我的其他答案中,我尽可能地做了少量更改以清楚地显示修复问题所需的更改。在这个答案中,我展示了我将如何写它:
_print:
cmp byte [rax], 0
jz _printSkip
mov rsi, rax
xor edx, edx
_printLoop:
inc edx
cmp byte [rsi+rdx], 0
jnz _printLoop
mov eax, 1
mov edi, 1
syscall
_printSkip:
ret
你能详细说明吗?它似乎不像第一个字符比较 – Mauricio
因此,事实上,“n”没有得到比较? – Mauricio
好,所以算法只是假设第一个字符是好的。谢谢 – Mauricio