转到汇编中用户输入的结尾

时间:2018-10-09 04:06:36

标签: assembly user-input x86-64

这是家庭作业,我需要转换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。

1 个答案:

答案 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的值呢? rcx

    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

因此,这似乎有很多问题。而且,是的。但是,即使您对确切的操作方式有点模糊,您似乎也正确地理解了自己要做什么。

希望这可以帮助您更好地了解正在发生的事情,并为您指明正确的方向。