Top.Mail.Ru
Ответы
Аватар пользователя
11 месяцев назад
от

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

(NASM, Win64, ld linker, Windows 11)
Почему этот код возвращает 5 как exit code, но если закомментировать 'mul R14', то он начинает возвращать 4?

123456789101112131415161718
 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 
Только авторизированные пользователи могут оставлять свои ответы
Дата
Популярность
Аватар пользователя
Знаток
11мес

Ваш код производит некорректный результат из-за неудачной комбинации инструкций. Давайте разберем проблему:

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. Попробуйте исправленный код и убедитесь, что он работает правильно.

Аватар пользователя
Оракул
11мес

Потому что после выполнения mul команда результат умножения устанавливается в RAX и RDX. После чего происходит обнуление RAX и запись в RAX с R15.

Аватар пользователя
11мес

Ну в угол поставьте, не будет больше себя так вести.

Аватар пользователя
Ученик
11мес

Проблема здесь в том, что после выполнения инструкции `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
```

Теперь код должен возвращать ожидаемые значения.

Аватар пользователя
Оракул
11мес

Код возвращает разные коды выхода (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