Слишком много, что я хочу сказать, чтобы уместиться в комментариях.Но так как я не планирую делать за вас домашнее задание, давайте посмотрим, смогу ли я объяснить проблемы, тогда вы можете их исправить.
Итак, начиная с верха:
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
Итак, это кажется большим количеством проблем.И да, вроде как.Но вы, кажется, правильно понимаете, что вы пытаетесь сделать, даже если вы немного не понимаете, как именно это сделать.
Надеюсь, это поможет вам понять, что происходит немного лучше, и укажет вам правильное направление.направление.