вывод аргумента

This commit is contained in:
mzhoot 2026-06-07 22:59:34 +03:00
parent 8c652e8aa0
commit b273f42984
5 changed files with 103 additions and 1 deletions

View file

@ -252,4 +252,6 @@ Pass2 (шаг 5):
сохранить_байт и загрузить_байт_из_памяти есть в INSTRUCTIONS, но не реализованы в диспетчере encode_instruction
пятый проход добавляет в разнобой свои добавления - адреса идет не по порядку
тестировать вытолкнуть
тестировать косвенную адресацию на р9-15
бага с двоеточием в строке

11
особенности Normal file
View file

@ -0,0 +1,11 @@
Косвенная адресация в КВС работает только через регистр R8 (и возможно R9R15 не работают или работают частично).
Инструкции, которые работают:
вытолкнуть (pop)
загрузить ал, [р8] (загрузка байта из памяти)
сравнить_с ал, 0 (сравнение с константой)
увеличить, переместить, исключающее_или
вызов_системы (syscall)
Строки в .данные не должны содержать символ : (двоеточие) — парсер обрезает.

View file

@ -0,0 +1,44 @@
.текст
.глобал _start
_start:
вытолкнуть рсикс
сравнить_с рсикс, 2
переход_если_меньше no_arg
вытолкнуть рсиай
вытолкнуть р8 ; argv[1] в R8
переместить рдиай, р8
исключающее_или рдикс, рдикс
strlen:
загрузить ал, [р8]
сравнить_с ал, 0
переход_если_равно strlen_done
увеличить р8
увеличить рдикс
переход strlen
strlen_done:
переместить_имм раикс, 1
переместить рсиай, рдиай
переместить_имм рдиай, 1
вызов_системы
исключающее_или рдиай, рдиай
переместить_имм раикс, 60
вызов_системы
no_arg:
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_no_arg
переместить_имм рдикс, 51
вызов_системы
переместить_имм рдиай, 1
переместить_имм раикс, 60
вызов_системы
.данные
msg_no_arg:
.строка "Ошибка не передан аргумент\n"

View file

@ -0,0 +1,29 @@
;./тесты/тест_адресации_р8.elf "A"
;echo $? # должен быть 65
; ============================================================
; тест_r8.квс - тест косвенной адресации через R8
; ============================================================
.текст
.глобал _start
_start:
; Получаем argv[1]
вытолкнуть рсикс ; argc
вытолкнуть рсиай ; argv[0]
вытолкнуть р8 ; argv[1] в R8
; Загружаем первый байт из argv[1] через R8
загрузить ал, [р8]
; Сохраняем в переменную (не обязательно, но для проверки)
сохранить [байт], ал
; Выход с кодом = загруженный байт
переместить_имм раикс, 60
загрузить рдиай, [байт]
вызов_системы
.данные
байт: .байт 0

16
черновик.txt Normal file
View file

@ -0,0 +1,16 @@
Резюме: Почему нужна специальная обработка рспикс/р12икс и рбпикс/р13икс
В архитектуре x86-64 байт ModR/M имеет исторические ограничения. Определенные значения в поле r/m (младшие 3 бита) имеют двойное значение в зависимости от поля mod. Если это не учесть, энкодер сгенерирует байты, которые выглядят логично, но процессор декодирует их совершенно иначе.
🪤 Ловушка №1: рспикс / р12икс (индекс 4)
Суть: В ModR/M значение r/m = 100 (десятичное 4) — это не код регистра. Это специальный сигнал процессору: "Следующий байт инструкции — это байт SIB (Scale-Index-Base)".
Что будет, если проигнорировать: Если закодировать [рспикс] просто как mod=00, r/m=4, процессор не остановится на этом байте. Он прочитает первый байт следующей инструкции (или данных) как байт SIB. Это вызовет сдвиг потока декодирования, превратив последующий код в бессмыслицу, что приведёт к SIGILL (недопустимая инструкция) или SIGSEGV.
Правильное решение: Для [рспикс] или [р12икс] энкодер обязан сгенерировать ModR/M с r/m=4, а сразу за ним — байт SIB 0x24 (где scale=00, index=100 (нет индекса), base=100 (rsp/r12)).
🪤 Ловушка №2: рбпикс / р13икс (индекс 5)
Суть: В 64-битном режиме комбинация mod=00 и r/m=101 (десятичное 5) зарезервирована исключительно под RIP-relative адресацию (например, [метка] для доступа к глобальным данным).
Что будет, если проигнорировать: Если попытаться закодировать честное [рбпикс] как mod=00, r/m=5, процессор проигнорирует тот факт, что вы хотели использовать регистр. Вместо этого он прочитает следующие 4 байта как 32-битное смещение относительно текущего указателя инструкций (RIP). Это приведёт к чтению мусора из памяти или крашу программы.
Правильное решение: Использовать mod=00 для этих регистров запрещено. Энкодер обязан принудительно переключиться на mod=01 (8-битное смещение) и добавить фиктивный байт смещения 0x00 сразу после ModR/M. Из-за этого инструкция [рбпикс] всегда на 1 байт длиннее, чем [раикс].
💡 Итог
Без этих двух проверок (if base == 4 и if base == 5) косвенная адресация через эти конкретные регистры будет тихо ломать выполнение программы. Это классические "грабли", на которые наступают почти все разработчики своих ассемблеров или JIT-компиляторов под x86-64.