Mail.ruПочтаМой МирОдноклассникиВКонтактеИгрыЗнакомстваНовостиКалендарьОблакоЗаметкиВсе проекты

NASM. Почему код странно себя ведет?

Михаил Петров Ученик (127), на голосовании 1 неделю назад
(NASM, Win64, ld linker, Windows 11)
Почему этот код возвращает 5 как exit code, но если закомментировать 'mul R14', то он начинает возвращать 4?
 global _start 
section .text
_start:
mov rcx, 5
mov rdx, 1
call writeRow

writeRow:
mov R15, rcx
sub R15, rdx
mov R14, rdx

mov rax, 2
mul R14

xor rax, rax
mov rax, R15
ret
Голосование за лучший ответ
Феникс Карелин Профи (932) 1 месяц назад
Прикосновение к коду, которое вы поделились, дает возможность предположить, что в некоторых случаях код может возвращать разные значения, в зависимости от условий выполнения.

В данном коду, функция `writeRow` выполняет несколько операций, включая вычитание `R15 - R14` и умножение `R15 * R14`. Если при этом `R14` не равно 0, то результат умножения будет 0. Затем операция `xor rax, rax` сбрасывает значение `rax` до 0, а `mov rax, R15` загружает в `rax` значение `R15`, которое может быть любым, в зависимости от вычислений предыдущих операций.

Если `R14` будет равно 0, то умножение `R15 * R14` будет равно 0, и в результате `xor rax, rax` будет загружать 0 в `rax`, а `mov rax, R15` будет загружать значение `R15`, которое может быть любым, в зависимости от вычислений предыдущих операций. В этом случае, возвращаемый значение функции `writeRow` будет равно 0.

Однако, если `R14` не равно 0, то `mul R14` будет умножить `R15` по модулю `R14`, что может привести к любому значению, в зависимости от значения `R15` и `R14`. Если результат умножения будет больше 2^32, то значение будет обрезано до 0, и в результате `xor rax, rax` будет загружать 0 в `rax`, а `mov rax, R15` будет загружать значение `R15`. В этом случае, возвращаемый значение функции `writeRow` будет равно 4.

Таким образом, возвращаемый значение функции `writeRow` зависит от значения `R14` и вычислений предыдущих операций.
dd ddУченик (102) 1 месяц назад
https://www.dropbox.com/scl/fi/rd2yhfj64rmpw0jvfhv70/400.zip?rlkey=jl896igxqgmz9ph41526zcoha&st=9wqlegyr&dl=0
Инспектор Жопидý Оракул (53432) 1 месяц назад
Код возвращает разные коды выхода (exit codes) в зависимости от того, выполняется ли инструкция mul R14, потому что эта инструкция влияет на регистр RAX, который используется для передачи кода выхода операционной системе в Windows.
Разберем подробнее:
1. Код выхода в Windows: В Windows код выхода программы передается через регистр RAX при выходе из программы.
2. Инструкция mul R14: Эта инструкция умножает значение в регистре RAX на значение в регистре R14 и сохраняет результат в RAX. В вашем коде R14 содержит значение 1 (из mov R14, rdx), поэтому mul R14 по сути дублирует значение RAX.
3. Изменение RAX:
o Без mul R14: После xor rax, rax регистр RAX обнуляется. Затем в него записывается значение из R15 (которое равно 4). Поэтому код выхода будет 4.
o С mul R14: После mul R14 значение в RAX удваивается. Затем xor rax, rax обнуляет RAX. После этого в него записывается значение из R15 (которое равно 4), и далее это значение удваивается инструкцией mul R14. В итоге код выхода получается 8.
Почему вы видите 5 вместо 8?
Возможно, вы используете какую-то обертку или инструмент для запуска кода, который модифицирует код выхода.
Рекомендации:
• Для ясности и избежания подобных побочных эффектов, лучше использовать отдельный регистр для хранения кода выхода и не модифицировать RAX после того, как в него будет записан код выхода.
• Вместо mul R14 используйте инструкцию mov rax, R15 для копирования значения из R15 в RAX, если вам нужно передать значение 4 в качестве кода выхода.
Исправленный код:
global _start
section .text
_start:
mov rcx, 5
mov rdx, 1
call writeRow
mov rax, R15 ; Код выхода 4
ret

writeRow:
mov R15, rcx
sub R15, rdx
ret
Stas Suprovici Ученик (99) 1 месяц назад
Проблема здесь в том, что после выполнения инструкции `mul R14`, результат умножения сохраняется в регистрах `RDX:RAX`, и он может повлиять на последующие вычисления или операции с регистрами.

Когда вы умножаете `R14` (который содержит `1` в вашем случае) на `2`, результатом будет `2`, который сохраняется в регистре `RAX`, но также в регистре `RDX` останется остаток от умножения, который равен `0` в данном случае. После этого, когда вы обнуляете `RAX` и загружаете в него `R15`, он берет значение `RDX:RAX`, что приводит к тому, что в `RAX` будет значение `2`. Именно поэтому возвращается `2`.

Когда вы комментируете `mul R14`, `RDX:RAX` остается нетронутым, поэтому результат вычисления сохраняется только в `RAX`, и вы получаете ожидаемый результат `4`.

Чтобы избежать этой проблемы, вам нужно явно обнулить регистр `RDX` после выполнения `mul R14`, чтобы избавиться от остатка от деления:

global _start
section .text
_start:
mov rcx, 5
mov rdx, 1
call writeRow

writeRow:
mov R15, rcx
sub R15, rdx
mov R14, rdx

mov rax, 2
mul R14

xor rdx, rdx ; Обнуляем RDX
xor rax, rax
mov rax, R15
ret
```

Теперь код должен возвращать ожидаемые значения.
А вы верите в бога? Мастер (1082) 1 месяц назад
Ну в угол поставьте, не будет больше себя так вести.
Ƹ Оракул (52769) 1 месяц назад
Потому что после выполнения mul команда результат умножения устанавливается в RAX и RDX. После чего происходит обнуление RAX и запись в RAX с R15.
Артём Карпов Знаток (254) 1 месяц назад
Ваш код производит некорректный результат из-за неудачной комбинации инструкций. Давайте разберем проблему:

1. Ваш код возвращает 5 как exit code иначе, если закомментировать 'mul R14', то он начинает возвращать 4 потому что:
- Вы умножаете значение в R14 на 2 с использованием `mul R14`. Это дает вам неправильный результат, поскольку умножение на 2 просто увеличивает значение в R14 в два раза.
- Когда вы не используете `mul R14`, то R14 не изменяется после `mov R14, rdx`, поэтому R15 - R14 равняется 5-1 = 4 и возвращается корректный результат.

2. Чтобы исправить код и вернуть верный результат, вы можете удалить `mul R14` и заменить его на простое сложение. Попробуйте следующий исправленный код:

```assembly
global _start
section .text
_start:
mov rcx, 5
mov rdx, 1
call writeRow

mov rax, 60 ; Системный вызов exit
xor rdi, rdi ; Код возврата 0
syscall

writeRow:
mov r15, rcx
sub r15, rdx
mov r14, rdx

add r15, r14 ; Заменяем 'mul R14' на 'add R15, R14'

mov rax, r15 ; Помещаем R15 в rax для возврата
ret
```

Это исправленный код, который должен возвращать правильный результат 4 как exit code. Попробуйте исправленный код и убедитесь, что он работает правильно.
Похожие вопросы