这是家庭作业,我需要转换64位(20个字符的用户输入)。十进制转换为十六进制
我的第一步是将char转换为十进制,因此我需要将ASCII
输入从用户输入转换为十进制。
如何移动并抓住用户输入的字符串的最后一个值 在组装吗?
假设我要一个数字,并且为了简单起见,用户在121
中键入,我知道它是在ASCII 31,32,31
字符中,因此我需要先将其转换为十进制,因此我想尽量减少有效数字,即最右边的一位到最高有效数字(从右到左)。
这是我的那部分代码:
initialize:
xor rax, rax ; initializes rax
mov rcx, 0 ; initialize rcx
mov rbx, 0 ; clear register to store result
mov rdx, 1 ; initliaze rdx to base 10 (10^0)
convertInputToDigits:
mov rcx, [count] ; initialize count
mov rsi, buf ; point to start of buffer
add rsi, [count] ; move to end of user input, this part may be wrong
mov rbx, [rsi-1] ; move the first rightmost number in rbx
sub rbx, '0' ; subtract hex value 30 for each character
; to get decimal value 0-9
mov rax, [rbx] ; move the result in rax
mul rdx ; multiply result, power of 10(rax*rdx)
add rbx, rax ; stores the total in rbx
dec rsi ; decrement up until first character
cmp rsi, 0 ; check if we are at the end of input/converted all input to decimal
je convertToHex ; if so jump to conversion
mov ax, [rdx] ; move value of rdx to ax
imul ax, 10 ; updates to the next power by 10*1 (10^1, 10^2)
jmp convertInputToDigits ; if not, loop again
我做错了什么以及如何解决它?
谢谢!
P.S。 output: 6296.
不知道它是怎么得到的,但绝对不是我需要转换的十进制121。
答案 0 :(得分:1)
我想说的太多了,不适合评论。但是由于我不打算为您做家庭作业,所以让我看看是否可以解释问题,然后您可以解决它们。
因此,从顶部开始:
initialize:
xor rax, rax ; initializes rax
此“初始化”对rax有何作用?你知道吗?如果这是课程,我将等你回答,但我将假设您已经知道它将rax设置为零。考虑到这一点,此行对rcx有什么作用?
mov rcx, 0 ; initialize rcx
显然,它将其设置为零。那么...为什么要使用两种不同的方法将寄存器设置为零?读起来有点混乱。另外,一个可能比另一个更有效,那么为什么不总是使用最高效的一个呢?哪一个最有效?参见this。
继续前进:
mov rbx, 0 ; clear register to store result
mov rdx, 1 ; initliaze rdx to base 10 (10^0)
我们将忽略拼写错误...
convertInputToDigits:
mov rcx, [count] ; initialize count
这不“初始化”计数。它从count指定的内存中读取当前值到rcx中。希望计数为8个字节长。因为这就是rcx的大小,所以这就是mov将要读取的字节数。您不会显示对count赋值,但是我希望您这样做。否则rcx只会包含垃圾。
mov rsi, buf ; point to start of buffer
add rsi, [count] ; move to end of user input, this part may be wrong
我不清楚您为什么在循环中包含这些行。当您到达循环的底部并跳回到convertInputToDigits
时,您不想将rsi重置为buf并再次添加“ count”。您想将rsi设置为一次,然后向后倒数。
实际上,您也不希望多次读取计数。
mov rbx, [rsi-1] ; move the first rightmost number in rbx
由于rbx的长度为8个字节,因此它将读取[rsi-1]的8个字节。正如我们所讨论的,这可能不是您想要的。
sub rbx, '0' ; subtract hex value 30 for each character
; to get decimal value 0-9
mov rax, [rbx] ; move the result in rax
您是否要将rbx副本复制到rax中?原因不是这个mov
所做的。相反,它将尝试从rbx中的内容指定的存储位置中读取。但是rbx中存储的不是内存位置(假设是数字1,对吗?)。因此,我希望这会因访问冲突而崩溃。
如果您确实想将rbx复制到rax中,那就只是mov rax, rbx
。
或者,为什么将值读入rbx并复制呢?为什么不首先使用rax?查看您的评论,您是否还会将RBX用于其他用途?
mul rdx ; multiply result, power of 10(rax*rdx)
好的,让我们谈谈它的作用。简而言之,它是RDX:RAX = RAX * RDX。虽然您仅指定RDX,但其余的则隐含。现在,“ RDX:RAX”是什么意思?好吧,如果RAX和RDX中的值确实很大,那么将它们相乘将导致结果太大而无法容纳在单个寄存器中。因此mul
使用2个寄存器保存结果。 RDX将是高位,而RAX将是低位。
对于121,您将永远不会获得足够大的结果来填充多个寄存器,因此RDX总是最终为零。下面将是一个问题。
add rbx, rax ; stores the total in rbx
存储总计是一件好事,这正是您要尝试执行的操作。但是您已经将rbx用于其他用途。因此,当您第二次通过循环时,rbx将不会获得第一个循环的结果。
dec rsi ; decrement up until first character
cmp rsi, 0 ; check if we are at the end of input/converted all input to decimal
je convertToHex ; if so jump to conversion
让我们花一点时间来讨论cmp / je的作用。简而言之,cmp进行比较,然后设置一些其他指令(例如je)可以使用的标志。然后je查看cmp设置的标志,并根据需要跳转。但是事实证明,cmp不是设置标志的唯一指令。 dec
也是如此。因此,您可以使用dec设置的标志来查看rsi是否为零,而无需执行额外的cmp。
(顺便说一句,如果您确实需要在没有进行dec
或其他操作的情况下检查零,则test rsi,rsi
的效率要比cmp rsi,0
略高)。
但是这里更重要的问题是rsi不会为零。使用我在评论中给出的示例:
如果rsi为(例如)0x100,则“ 121”的3个字节分别为0x100、0x101和0x102。
因此,如果我们从0x103开始(通常地址会大很多),那么对于我们的三位数字,每位递减一次,我们就不会寻找零。那么,我们可以递减当前值为3的值呢?
mov ax, [rdx] ; move value of rdx to ax
还记得我说过将rdx设置为零会出现问题吗?好吧,这是。如果rdx为零,则您正在尝试读取内存位置[0]。这将是访问冲突。由于rdx将在每个循环中清零,因此也许您应该选择一个不同的寄存器来存储功率。
imul ax, 10 ; updates to the next power by 10*1 (10^1, 10^2)
这种形式的imul将有效地执行ax = ax *10。但是ax是否要存储结果呢?
jmp convertInputToDigits ; if not, loop again
因此,这似乎有很多问题。而且,是的。但是,即使您对确切的操作方式有点模糊,您似乎也正确地理解了自己要做什么。
希望这可以帮助您更好地了解正在发生的事情,并为您指明正确的方向。