Переход к концу пользовательского ввода в сборке - PullRequest
0 голосов
/ 09 октября 2018

Это домашнее задание, и мне нужно преобразовать 64-битный (20 символов ввода пользователя).десятичное в шестнадцатеричное

мой первый шаг - преобразование символа в десятичное, поэтому мне нужно преобразовать ввод 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

Что я делаю не так и как это исправить?

Спасибо!

PS output: 6296. Не знаю, как это получилось, но определенно не десятичный 121, который мне нужен для преобразования.

1 Ответ

0 голосов
/ 10 октября 2018

Слишком много, что я хочу сказать, чтобы уместиться в комментариях.Но так как я не планирую делать за вас домашнее задание, давайте посмотрим, смогу ли я объяснить проблемы, тогда вы можете их исправить.

Итак, начиная с верха:

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 байтов, это будет считывать 8 байтов в [rsi - 1].Как мы уже говорили, это, вероятно, не то, что вы хотели.

    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).Затем он смотрит на флаги, установленные cmp, и переходит соответственно.Но оказывается, что cmp - не единственная инструкция, которая устанавливает флаги.Так же dec.Таким образом, вы можете увидеть, достиг ли rsi нулевого значения, используя флаги, установленные с помощью dec, без необходимости делать дополнительные cmp.

(Кстати, если вам когда-либо нужно проверять ноль, не выполнив dec или что-то в этом роде), test rsi,rsi немного более эффективен, чем cmp rsi,0).

Но более важной проблемой здесь является то, что rsi не будет равным нулю.Используя пример, который я дал в моих комментариях:

Если rsi (скажем) 0x100, то 3 байта "121" будут иметь значения 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

Итак, это кажется большим количеством проблем.И да, вроде как.Но вы, кажется, правильно понимаете, что вы пытаетесь сделать, даже если вы немного не понимаете, как именно это сделать.

Надеюсь, это поможет вам понять, что происходит немного лучше, и укажет вам правильное направление.направление.

...