这是一个简单的问题,但它使我的头旋转。我需要将一串字符字符串(输入为负十进制数字(转换为一个无符号整数。RDI寄存器包含要转换的字符串。RAX寄存器将保持结果。
xor rsi, rsi
xor rax, rax
xor dl, dl
xor rdx, rdx
convert:
mov dl, [rdi+rsi] ;+rsi causes segmentation fault
cmp dl, "-"
jz increment
cmp dl, "."
jz dtoi_end
sub dl, "0"
mov rdx, 10
mul rdx
add rax, dl ;invalid combination
inc rsi
jmp convert
increment:
inc rsi
jmp convert
convert_end:
ret
我需要迭代每个字符,并且我正在尝试使用RSI寄存器来使用它。但是每次尝试此操作时,我都会得到一个细分错误。
无效的组合误差。我知道这是因为寄存器的大小不同,但是我迷失了如何继续将转换后的ASCII值添加回RAX。
这里有一个类似的问题可以帮助我更好地理解这一过程,但是我已经撞到了一堵墙:将字符串转换为int。x86 32位汇编器使用nasm
我需要迭代每个字符,并且我试图通过使用RSI寄存器来使用它。但是每次尝试此操作时,我都会得到一个细分错误。
基于您显示的代码以及RDI
的语句保留字符串开始的地址,我可以看到一些不同的原因,为什么您会在该负载中获得分割错误。
也许问题是RDI
包含一个8个字符ASCII字符串(通过值通过(,而不是包含字符串的内存位置的地址(通过参考通过(?
另一个可能性的可能性是它在循环的前几个迭代中正常工作,但是随后您开始尝试读取字符串末端,因为您无法正确终止循环。您显示的代码中没有dtoi_end
标签,也没有您实际跳到convert_end
标签的位置。这些应该是同一标签吗?如果我通过字符串" -2"会怎样?您的循环何时终止?在我看来,它不会!
您需要某种方法来指示整个字符串已经处理过。有几种常见方法。一个人在字符串末端使用哨兵终结器字符,就像C与ASCIINUL字符一样。在循环的内部,您会检查要处理的角色是否为0(NUL(,如果是的,请跳出循环。另一个选项是将字符串的长度作为附加参数传递给该函数,就像帕斯卡(Pascal(使用计数长度字符串一样。然后,您将在循环的内部进行测试,检查是否已经处理过足够的字符,如果是的话,请跳出循环。
我会尽量不要对此过于讲道,但是您应该能够通过使用调试器自己发现这个问题。逐步执行逐条执行,观察变量/寄存器的值,并确保您了解正在发生的事情。这基本上是我在分析您的代码时所做的,除了我将头作为调试器,"在我自己的脑海中执行"代码。不过,让计算机这样做要容易得多(且容易出错(,这就是为什么发明辩论者的原因。如果您的代码不起作用,并且还没有在调试器中逐条逐步浏览它,那么您还没有努力工作以自己解决问题。实际上,通过单步步您编写的每个功能都是一个很好的习惯,因为(a(它将确保您了解所写的内容的逻辑,并且(b('将帮助您找到错误。
无效的组合错误。我知道这是因为寄存器的大小不同,但是我迷失了如何继续将转换后的ASCII值添加到RAX中。
您必须使大小匹配。您可以执行add al, dl
,但是您将结果将结果限制为8位字节。那可能不是你想要的。因此,您需要将dl
制成64位QWOWS,例如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
。
只是为了娱乐,这是代码的可能实现:
; 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
(警告:未经测试的逻辑!我只是以更优化的方式重写了您的现有代码,而没有错误。(