我需要遍历每个字符,并且我正在尝试通过使用 rsi 寄存器来使用它。但是每次我尝试这个时,我都会遇到分段错误。
根据您显示的代码,以及 RDI 保存字符串开头地址的语句,我可以看到导致该负载出现分段错误的几个不同原因。
也许问题在于RDI 包含一个 8 字符的 ASCII 字符串(按值传递),而不是包含该字符串的内存位置的地址(按引用传递)?
另一个更可能的可能性是它在循环的前几次迭代中运行良好,但随后您开始尝试读取字符串的末尾,因为您没有正确终止循环。您显示的代码中没有dtoi_end 标签,也没有您实际跳转到convert_end 标签的地方。这些应该是同一个标签吗?如果我传入字符串“-2”会发生什么?您的循环何时终止?在我看来它不会!
您需要某种方式来表明整个字符串已被处理。有几种常用的方法。一种是在字符串末尾使用标记终止符,就像 C 对 ASCII NUL 字符所做的那样。在循环内部,您将检查正在处理的字符是否为 0 (NUL),如果是,则跳出循环。另一种选择是将字符串的长度作为附加参数传递给函数,就像 Pascal 对计数长度字符串所做的那样。然后,您将在循环内进行测试,检查您是否已经处理了足够多的字符,如果是,则跳出循环。
我会尽量不要太说教,但您应该能够通过使用调试器自己检测到这个问题。逐行执行代码,查看变量/寄存器的值,并确保您了解正在发生的事情。这基本上是我在分析你的代码时所做的,除了我用我的头作为调试器,在我自己的脑海中“执行”代码。不过,让计算机来做这件事要容易得多(而且不容易出错),这就是发明调试器的原因。如果您的代码不工作,并且您没有在调试器中逐行执行它,那么您还没有足够努力地自己解决问题。事实上,单步执行你编写的每个函数是一个很好的习惯,因为 (A) 它会确保你理解你所写内容的逻辑,并且 (B) 它'将帮助您找到错误。
无效的组合错误。我知道这是因为寄存器的大小不同,但我不知道如何继续将转换后的 ascii 值添加回 rax。
您必须使尺寸匹配。您可以执行add al, dl,但您会将结果限制为 8 位字节。这可能不是你想要的。所以,你需要把dl 变成一个64 位的QWORD,比如rax。最明显的方法是使用MOVZX 指令,该指令执行零扩展。换句话说,它将值“扩展”到更大的大小,用 0 填充高位。这就是您想要的无符号值。对于有符号值,您需要进行符号感知扩展(即考虑符号位),为此,您将使用MOVSX 指令。
在代码中:
movzx rdx, dl
add rax, rdx
请注意,正如其中一位评论者所指出的,DL 只是RDX 寄存器的最低 8 位:
| 63 - 32 | 31 - 16 | 15 - 8 | 7 - 0 |
--------------------------------------
| DH | DL |
--------------------------------------
| EDX |
--------------------------------------
| RDX |
因此,xor dl, dl 和 xor rdx, rdx 是多余的。后者完成了前者。另外,每次修改dl,实际上都是在修改rdx的最低8位,这会导致结果不正确。提示,提示:这是您可以通过使用调试器单步执行的其他操作(尽管您可能不明白为什么!)。
而且,xor rdx, rdx 完全没有必要!您可以通过 xor edx, edx 完成相同的任务,more efficiently。
只是为了好玩,这是代码的一种可能实现:
; Parameters: RDI == address of start of character string
; RCX == number of characters in string
; Clobbers: RDX, RSI
; Returns: result is in RAX
xor esi, esi
convert:
; See if we've done enough characters by checking the length of the string
; against our current index.
cmp rsi, rcx
jge convert_end
; Get the next character from the string.
mov dl, BYTE [rdi + rsi]
cmp dl, "-"
je increment
cmp dl, "."
je convert_end
; Efficient way to multiply by 10.
; (Faster and less difficult to write than the MUL instruction.)
add rax, rax
lea rax, [4 * rax + rax]
sub dl, "0"
movzx rdx, dl
add rax, rdx
; (fall through to increment---no reason for redundant instructions!)
increment:
inc rsi ; increment index/counter
jmp convert ; keep looping
convert_end:
ret
(警告:此逻辑未经测试!我只是以更优化的方式重写了您现有的代码,没有错误。)