From b273f4298426b6bf0d6a4857919e4f7bfb576481 Mon Sep 17 00:00:00 2001 From: mzhoot Date: Sun, 7 Jun 2026 22:59:34 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=20=D0=B0=D1=80?= =?UTF-8?q?=D0=B3=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- todo.txt | 4 +- особенности | 11 +++++ .../вывод_аргумента.квс | 44 +++++++++++++++++++ .../тест_адресации_р8.квс | 29 ++++++++++++ черновик.txt | 16 +++++++ 5 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 особенности create mode 100644 тесты/вывод_аргумента.квс create mode 100644 тесты/тест_адресации_р8.квс create mode 100644 черновик.txt diff --git a/todo.txt b/todo.txt index 60daa9c..27b6a87 100644 --- a/todo.txt +++ b/todo.txt @@ -252,4 +252,6 @@ Pass2 (шаг 5): сохранить_байт и загрузить_байт_из_памяти есть в INSTRUCTIONS, но не реализованы в диспетчере encode_instruction -пятый проход добавляет в разнобой свои добавления - адреса идет не по порядку \ No newline at end of file +тестировать вытолкнуть +тестировать косвенную адресацию на р9-15 +бага с двоеточием в строке \ No newline at end of file diff --git a/особенности b/особенности new file mode 100644 index 0000000..0cedf17 --- /dev/null +++ b/особенности @@ -0,0 +1,11 @@ + Косвенная адресация в КВС работает только через регистр R8 (и возможно R9–R15 не работают или работают частично). + + Инструкции, которые работают: + вытолкнуть (pop) + загрузить ал, [р8] (загрузка байта из памяти) + сравнить_с ал, 0 (сравнение с константой) + увеличить, переместить, исключающее_или + вызов_системы (syscall) + + Строки в .данные не должны содержать символ : (двоеточие) — парсер обрезает. + diff --git a/тесты/вывод_аргумента.квс b/тесты/вывод_аргумента.квс new file mode 100644 index 0000000..54960d1 --- /dev/null +++ b/тесты/вывод_аргумента.квс @@ -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" \ No newline at end of file diff --git a/тесты/тест_адресации_р8.квс b/тесты/тест_адресации_р8.квс new file mode 100644 index 0000000..c001020 --- /dev/null +++ b/тесты/тест_адресации_р8.квс @@ -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 \ No newline at end of file diff --git a/черновик.txt b/черновик.txt new file mode 100644 index 0000000..bfa59a7 --- /dev/null +++ b/черновик.txt @@ -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. \ No newline at end of file