From 3493d06200a65501aa2fd9f53e839e72f85113b8 Mon Sep 17 00:00:00 2001 From: mzhoot Date: Sat, 27 Jun 2026 13:33:19 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D1=87=D0=B8=D0=BD=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20=D1=8012=20=D0=B8=20sib-=D0=B1=D0=B0=D0=B9=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kvs_encoder_mutsize.py | 42 +++-- тесты/kvs_full_test.csv | 3 +- .../тест_адресации_р12.py | 145 ++++++++++++++++++ .../тест_адресации_р12.квс | 29 ++++ .../черновик/черновик.квс | 31 ++-- 5 files changed, 229 insertions(+), 21 deletions(-) create mode 100644 тесты/тест_адресации_р12/тест_адресации_р12.py create mode 100644 тесты/тест_адресации_р12/тест_адресации_р12.квс diff --git a/kvs_encoder_mutsize.py b/kvs_encoder_mutsize.py index 5c49282..d003e7f 100644 --- a/kvs_encoder_mutsize.py +++ b/kvs_encoder_mutsize.py @@ -189,6 +189,10 @@ def encode_mov_mem_reg_absolute(reg_info, mem_info, current_pos, vaddr_text): def encode_mov_reg_mem_indirect(reg_info: dict, base_reg: str) -> bytearray: """ Кодирует MOV reg, [base_reg] — косвенная адресация через регистр. + + Особые случаи x86-64: + - [rsp] и [r12] (индексы 4 и 12) требуют SIB-байта при mod=00 + - [rbp] и [r13] (индексы 5 и 13) требуют disp8=0 при mod=00 """ code = bytearray() @@ -239,16 +243,29 @@ def encode_mov_reg_mem_indirect(reg_info: dict, base_reg: str) -> bytearray: if base_index >= 8: rex |= 0x01 # REX.B = 1 - # === 4. Формируем ModR/M байт === - if (base_index & 7) == 5: - # [rbp] или [r13] требуют disp8=0 - modrm = 0x40 | ((reg_index & 7) << 3) | 5 - modrm_byte = modrm - disp8 = 0x00 - else: - modrm = ((reg_index & 7) << 3) | (base_index & 7) - modrm_byte = modrm + # === 4. Формируем ModR/M и SIB байты === + base_low = base_index & 7 # младшие 3 бита индекса + + if base_low == 4: + # Особый случай: [rsp] или [r12] — требуется SIB-байт + # В x86-64 mod=00 с r/m=4 означает [SIB] без смещения + # SIB: base=4 (rsp/r12), index=4 (нет индексного регистра), scale=0 + modrm_byte = 0x00 | ((reg_index & 7) << 3) | 0x04 + sib_byte = 0x20 | (4 << 3) | 4 # scale=0, index=4(нет), base=4 disp8 = None + has_sib = True + elif base_low == 5: + # Особый случай: [rbp] или [r13] — требуется disp8=0 + # В x86-64 mod=00 с r/m=5 означает [RIP+disp32], + # поэтому для [rbp]/[r13] используем mod=01 с disp8=0 + modrm_byte = 0x40 | ((reg_index & 7) << 3) | 0x05 + disp8 = 0x00 + has_sib = False + else: + # Обычный случай: [reg] — mod=00, без SIB, без смещения + modrm_byte = ((reg_index & 7) << 3) | base_low + disp8 = None + has_sib = False # === 5. Собираем инструкцию === @@ -266,12 +283,17 @@ def encode_mov_reg_mem_indirect(reg_info: dict, base_reg: str) -> bytearray: # 5d. ModR/M байт code.append(modrm_byte) - # 5e. Disp8 (если есть) + # 5e. SIB байт (только для RSP/R12) + if has_sib: + code.append(sib_byte) + + # 5f. Disp8 (только для RBP/R13) if disp8 is not None: code.append(disp8) return code + def encode_mov_mem_reg_indirect(base_reg, reg_info): """ Кодирует MOV [base_reg], reg — косвенная адресация. diff --git a/тесты/kvs_full_test.csv b/тесты/kvs_full_test.csv index ebb4806..85c1f13 100644 --- a/тесты/kvs_full_test.csv +++ b/тесты/kvs_full_test.csv @@ -20,4 +20,5 @@ 1;тест_адресации_р13;Проверка косвенной адресации через R13 (ASCII код первого символа аргумента) 1;тест_адресации_р14;Проверка косвенной адресации через R14 (ASCII код первого символа аргумента) 1;тест_адресации_р15;Проверка косвенной адресации через R15 (ASCII код первого символа аргумента) -1;двоеточие_в_строке;Проверка обработки строк с двоеточием внутри \ No newline at end of file +1;двоеточие_в_строке;Проверка обработки строк с двоеточием внутри +1;тест_адресации_р12;Проверка косвенной адресации через R12 (ASCII код первого символа аргумента) \ No newline at end of file diff --git a/тесты/тест_адресации_р12/тест_адресации_р12.py b/тесты/тест_адресации_р12/тест_адресации_р12.py new file mode 100644 index 0000000..7aeb5ef --- /dev/null +++ b/тесты/тест_адресации_р12/тест_адресации_р12.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Тест для проверки косвенной адресации через регистр R12 +Запускает скомпилированную программу с различными аргументами +и проверяет код возврата (должен быть равен ASCII коду первого символа) +""" + +import subprocess +import sys +import os +from pathlib import Path + +# Определяем пути +SCRIPT_DIR = Path(__file__).parent.absolute() +PROJECT_ROOT = SCRIPT_DIR.parent.parent +SOURCE_REL = SCRIPT_DIR / "тест_адресации_р12.квс" + +def clean(): + """Очищает артефакты сборки""" + files = [ + "тест_адресации_р12.elf", + "тест_адресации_р12.csv", + "тест_адресации_р12.аст", + "тест_адресации_р12.токены", + "тест_адресации_р12.константа", + "тест_адресации_р12_pass4.log" + ] + for f in files: + f_path = SCRIPT_DIR / f + if f_path.exists(): + f_path.unlink() + print(f"DEBUG: Удалён {f}", file=sys.stderr) + +def build() -> bool: + """ + Собирает тестовую программу с помощью КВС + + Returns: + bool: True если сборка успешна, иначе False + """ + print(f"DEBUG: Сборка {SOURCE_REL}", file=sys.stderr) + os.chdir(PROJECT_ROOT) + + build = subprocess.run( + ["python3", "квс_сборка.py", str(SOURCE_REL)], + capture_output=True, + text=True + ) + + if build.returncode != 0: + print(f"❌ Ошибка сборки: {build.returncode}", file=sys.stderr) + print(build.stderr, file=sys.stderr) + return False + + print("DEBUG: Сборка успешна", file=sys.stderr) + return True + +def test_with_char(char: str, expected_code: int) -> bool: + """ + Запускает скомпилированную программу с одним символом в качестве аргумента + и проверяет код возврата + + Args: + char: символ для передачи в программу + expected_code: ожидаемый ASCII код символа + + Returns: + bool: True если код возврата совпадает с ожидаемым, иначе False + """ + print(f"DEBUG: Тест с символом '{char}' (ожидается код {expected_code})", file=sys.stderr) + os.chdir(SCRIPT_DIR) + + elf_path = SCRIPT_DIR / "тест_адресации_р12.elf" + if not elf_path.exists(): + print("❌ ELF файл не найден", file=sys.stderr) + return False + + # Запускаем программу с аргументом + run = subprocess.run( + [str(elf_path), char], + capture_output=True, + text=True + ) + + # Проверяем код возврата (должен быть ASCII код символа) + if run.returncode != expected_code: + print(f"❌ Код возврата: ожидался {expected_code}, получен {run.returncode}", file=sys.stderr) + if run.stderr: + print(f" stderr: {run.stderr}", file=sys.stderr) + if run.stdout: + print(f" stdout: {run.stdout}", file=sys.stderr) + return False + + print(f"DEBUG: Тест с символом '{char}' пройден (код {run.returncode})", file=sys.stderr) + return True + +def main(): + """Главная функция теста""" + print("DEBUG: Начало теста тест_адресации_р12", file=sys.stderr) + + # Собираем программу + if not build(): + clean() + sys.exit(1) + + # Тестируем разные символы + tests = [ + ('A', 65), # Латинская A + ('B', 66), # Латинская B + ('0', 48), # Цифра 0 + ('z', 122), # Латинская z + ('!', 33), # Восклицательный знак + ('x', 120), # Латинская x + ('5', 53), # Цифра 5 + ('_', 95), # Подчёркивание + ('$', 36), # Знак доллара + ('@', 64), # Собака + ('#', 35), # Решётка + ('*', 42), # Звёздочка + ('~', 126), # Тильда + (' ', 32), # Пробел + ('\t', 9), # Табуляция (может не сработать из-за экранирования) + ] + + all_passed = True + + for char, expected_code in tests: + if not test_with_char(char, expected_code): + all_passed = False + break + + # Очищаем артефакты + clean() + + if all_passed: + print("✅ Все тесты пройдены!", file=sys.stderr) + sys.exit(0) + else: + print("❌ Тест провален", file=sys.stderr) + sys.exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/тесты/тест_адресации_р12/тест_адресации_р12.квс b/тесты/тест_адресации_р12/тест_адресации_р12.квс new file mode 100644 index 0000000..f093d8b --- /dev/null +++ b/тесты/тест_адресации_р12/тест_адресации_р12.квс @@ -0,0 +1,29 @@ +;./тесты/тест_адресации_р12.elf "A" +;echo $? # должен быть 65 + +; ============================================================ +; тест_адресации_r12.квс - тест косвенной адресации через R12 +; ============================================================ + +.текст +.глобал _start + +_start: + ; Получаем argv[1] + вытолкнуть рсикс ; argc + вытолкнуть рсиай ; argv[0] + вытолкнуть р12 ; argv[1] в R12 + + ; Загружаем первый байт из argv[1] через R12 + загрузить ал, [р12] + + ; Сохраняем в переменную (не обязательно, но для проверки) + сохранить [байт], ал + + ; Выход с кодом = загруженный байт + переместить_имм раикс, 60 + загрузить рдиай, [байт] + вызов_системы + +.данные +байт: .байт 0 \ No newline at end of file diff --git a/тесты/черновик/черновик.квс b/тесты/черновик/черновик.квс index 773d2ba..5bf4f44 100644 --- a/тесты/черновик/черновик.квс +++ b/тесты/черновик/черновик.квс @@ -1,18 +1,29 @@ +;./тесты/тест_адресации_р11.elf "A" +;echo $? # должен быть 65 + +; ============================================================ +; тест_адресации_r11.квс - тест косвенной адресации через R11 +; ============================================================ + .текст .глобал _start _start: - ; Системный вызов write(1, msg, len) - переместить_имм раикс, 1 ; номер syscall write = 1 - переместить_имм рдиай, 1 ; stdout = 1 - переместить_имм рсиай, msg ; указатель на строку - переместить_имм рдикс, 21 ; длина строки - вызов_системы + ; Получаем argv[1] + вытолкнуть рсикс ; argc + вытолкнуть рсиай ; argv[0] + вытолкнуть р12 ; argv[1] в R12 - ; Системный вызов: exit(0) - переместить_имм раикс, 60 ; номер syscall exit = 60 - переместить_имм рдиай, 0 ; код возврата + ; Загружаем первый байт из argv[1] через R12 + загрузить ал, [р12] + + ; Сохраняем в переменную (не обязательно, но для проверки) + сохранить [байт], ал + + ; Выход с кодом = загруженный байт + переместить_имм раикс, 60 + загрузить рдиай, [байт] вызов_системы .данные -msg: .строка "Приве : мир!\n" \ No newline at end of file +байт: .байт 0 \ No newline at end of file