вывод аргумента
This commit is contained in:
parent
8c652e8aa0
commit
b273f42984
4
todo.txt
4
todo.txt
|
|
@ -252,4 +252,6 @@ Pass2 (шаг 5):
|
|||
|
||||
сохранить_байт и загрузить_байт_из_памяти есть в INSTRUCTIONS, но не реализованы в диспетчере encode_instruction
|
||||
|
||||
пятый проход добавляет в разнобой свои добавления - адреса идет не по порядку
|
||||
тестировать вытолкнуть
|
||||
тестировать косвенную адресацию на р9-15
|
||||
бага с двоеточием в строке
|
||||
11
особенности
Normal file
11
особенности
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Косвенная адресация в КВС работает только через регистр R8 (и возможно R9–R15 не работают или работают частично).
|
||||
|
||||
Инструкции, которые работают:
|
||||
вытолкнуть (pop)
|
||||
загрузить ал, [р8] (загрузка байта из памяти)
|
||||
сравнить_с ал, 0 (сравнение с константой)
|
||||
увеличить, переместить, исключающее_или
|
||||
вызов_системы (syscall)
|
||||
|
||||
Строки в .данные не должны содержать символ : (двоеточие) — парсер обрезает.
|
||||
|
||||
44
тесты/вывод_аргумента.квс
Normal file
44
тесты/вывод_аргумента.квс
Normal 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"
|
||||
29
тесты/тест_адресации_р8.квс
Normal file
29
тесты/тест_адресации_р8.квс
Normal 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
16
черновик.txt
Normal 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.
|
||||
Loading…
Reference in a new issue