#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ kvs_data.py Общие данные для КВС - ассемблера Регистры, инструкции, константы и вспомогательные функции """ import struct # === ГЛОБАЛЬНЫЕ КОНСТАНТЫ === # ELF константы PAGE_SIZE = 0x1000 # Размер страницы памяти (4096 байт) elf_base_vaddr = 0x400000 # Базовый виртуальный адрес ELF text_vaddr_base = 0x401000 # Базовый адрес секции .text data_vaddr_base = 0x402000 # Базовый адрес секции .data # === РЕГИСТРЫ (64, 32, 16, 8-битные) === # Индексы используются для кодирования в ModR/M и REX префиксах REGISTERS = { # 64-битные полные регистры "раикс": 0, # RAX - аккумулятор (результаты арифметики, возвращаемые значения) "рсикс": 1, # RCX - счётчик (счётчик циклов, второй аргумент) "рдикс": 2, # RDX - данные (третий аргумент, остаток от деления) "рбикс": 3, # RBX - база (базовый регистр, сохраняется между вызовами) "рсипи": 4, # RSP - указатель стека (вершина стека) "рбипи": 5, # RBP - указатель базы (кадр стека) "рсиай": 6, # RSI - индекс источника (второй аргумент, строковые операции) "рдиай": 7, # RDI - индекс назначения (первый аргумент, строковые операции) "р8": 8, # R8 (общего назначения, восьмой) "р9": 9, # R9 (общего назначения, девятый) "р10": 10, # R10 (общего назначения, десятый) "р11": 11, # R11 (общего назначения, одиннадцатый) "р12": 12, # R12 (общего назначения, двенадцатый) "р13": 13, # R13 (общего назначения, тринадцатый) "р14": 14, # R14 (общего назначения, четырнадцатый) "р15": 15, # R15 (общего назначения, пятнадцатый) # 32-битные младшие части (обнуляют старшие 32 бита при записи) "еаикс": 0, # EAX - младшие 32 бита RAX "есикс": 1, # ECX - младшие 32 бита RCX "едикс": 2, # EDX - младшие 32 бита RDX "ебикс": 3, # EBX - младшие 32 бита RBX "есипи": 4, # ESP - младшие 32 бита RSP "ебипи": 5, # EBP - младшие 32 бита RBP "есиай": 6, # ESI - младшие 32 бита RSI "едиай": 7, # EDI - младшие 32 бита RDI "р8д": 8, # R8D - младшие 32 бита R8 "р9д": 9, # R9D - младшие 32 бита R9 "р10д": 10, # R10D - младшие 32 бита R10 "р11д": 11, # R11D - младшие 32 бита R11 "р12д": 12, # R12D - младшие 32 бита R12 "р13д": 13, # R13D - младшие 32 бита R13 "р14д": 14, # R14D - младшие 32 бита R14 "р15д": 15, # R15D - младшие 32 бита R15 # 16-битные младшие части (не обнуляют старшие биты) "аикс": 0, # AX - младшие 16 бит RAX "сикс": 1, # CX - младшие 16 бит RCX "дикс": 2, # DX - младшие 16 бит RDX "бикс": 3, # BX - младшие 16 бит RBX "эсп": 4, # SP - младшие 16 бит RSP "бипи": 5, # BP - младшие 16 бит RBP "эс": 6, # SI - младшие 16 бит RSI "ди": 7, # DI - младшие 16 бит RDI "р8в": 8, # R8W - младшие 16 бит R8 "р9в": 9, # R9W - младшие 16 бит R9 "р10в": 10, # R10W - младшие 16 бит R10 "р11в": 11, # R11W - младшие 16 бит R11 "р12в": 12, # R12W - младшие 16 бит R12 "р13в": 13, # R13W - младшие 16 бит R13 "р14в": 14, # R14W - младшие 16 бит R14 "р15в": 15, # R15W - младшие 16 бит R15 # 8-битные младшие части "ал": 0, # AL - младший байт AX (биты 0-7) "кл": 1, # CL - младший байт CX (используется в сдвигах) "дл": 2, # DL - младший байт DX "бл": 3, # BL - младший байт BX "спл": 4, # SPL - младший байт SP "бпл": 5, # BPL - младший байт BP "сил": 6, # SIL - младший байт SI "дил": 7, # DIL - младший байт DI "р8б": 8, # R8B - младший байт R8 "р9б": 9, # R9B - младший байт R9 "р10б": 10, # R10B - младший байт R10 "р11б": 11, # R11B - младший байт R11 "р12б": 12, # R12B - младший байт R12 "р13б": 13, # R13B - младший байт R13 "р14б": 14, # R14B - младший байт R14 "р15б": 15, # R15B - младший байт R15 # 8-битные старшие части (только для первых 4 регистров) "аш": 0, # AH - старший байт AX (биты 8-15) "чш": 1, # CH - старший байт CX "дш": 2, # DH - старший байт DX "бш": 3, # BH - старший байт BX } # === ИНСТРУКЦИИ === # Каждая инструкция содержит opcode (последовательность байт) и, # при необходимости, дополнительные параметры (например, subop для INC/DEC) INSTRUCTIONS = { # === Инструкции перемещения данных === "переместить_имм": {"opcode": None}, # MOV reg, imm "переместить": {"opcode": b"\x48\x89"}, # MOV reg, reg "загрузить": {"opcode": b"\x48\x8B"}, # MOV reg, mem "сохранить": {"opcode": b"\x48\x89"}, # MOV mem, reg "загрузить_байт_из_памяти": {"opcode": b"\x8A"}, # MOV reg8, mem8 "сохранить_байт": {"opcode": b"\x88"}, # MOV mem8, reg8 "загрузить_адрес": {"opcode": b"\x48\x8D"}, # LEA reg, mem "переместить_с_нулями": {"opcode": b"\x48\x0F\xB6"}, # MOVZX reg, mem8 "переместить_со_знаком": {"opcode": b"\x48\x0F\xBE"}, # MOVSX reg, mem8 "загрузить_байт": {"opcode": None}, # MOV reg8, imm8 # === Инструкции сравнения === "сравнить_с": {"opcode": None}, # CMP reg, imm "сравнить": {"opcode": b"\x48\x39"}, # CMP reg, reg "сравнить_байт": {"opcode": b"\x38"}, # CMP reg8, reg8 "проверить": {"opcode": b"\x48\x85"}, # TEST reg, reg # === Арифметические инструкции === "прибавить": {"opcode": b"\x48\x01"}, # ADD reg, reg "прибавить_непосредственно": {"opcode": None}, # ADD reg, imm "прибавить_байт": {"opcode": b"\x00"}, # ADD reg8, reg8 "вычесть": {"opcode": b"\x48\x29"}, # SUB reg, reg "вычесть_непосредственно": {"opcode": None}, # SUB reg, imm "вычесть_байт": {"opcode": b"\x28"}, # SUB reg8, reg8 "увеличить": {"opcode": b"\xFF", "subop": 0}, # INC reg "уменьшить": {"opcode": b"\xFF", "subop": 1}, # DEC reg # Умножение и деление "умножить": {"opcode": b"\xF7", "subop": 4}, # MUL reg/mem "умножить_знаковое": {"opcode": b"\xF7", "subop": 5}, # IMUL reg/mem "разделить": {"opcode": b"\xF7", "subop": 6}, # DIV reg/mem "разделить_знаковое": {"opcode": b"\xF7", "subop": 7}, # IDIV reg/mem # === Логические инструкции === "и": {"opcode": b"\x48\x21"}, # AND reg, reg "или": {"opcode": b"\x48\x09"}, # OR reg, reg "исключающее_или": {"opcode": b"\x48\x31"}, # XOR reg, reg "инвертировать": {"opcode": b"\xF7", "subop": 2}, # NOT reg "отрицать": {"opcode": b"\xF7", "subop": 3}, # NEG reg # === Инструкции переходов и вызовов === "переход": {"opcode": b"\xE9"}, # JMP rel32 "короткий_переход": {"opcode": b"\xEB"}, # JMP SHORT rel8 # Длинные условные переходы (32-битное смещение) "переход_если_равно": {"opcode": b"\x0F\x84"}, # JE/JZ "переход_если_неравно": {"opcode": b"\x0F\x85"}, # JNE/JNZ "переход_если_меньше": {"opcode": b"\x0F\x8C"}, # JL "переход_если_больше": {"opcode": b"\x0F\x8F"}, # JG "переход_если_меньше_или_равно": {"opcode": b"\x0F\x8E"}, # JLE "переход_если_больше_или_равно": {"opcode": b"\x0F\x8D"}, # JGE "переход_если_перенос": {"opcode": b"\x0F\x82"}, # JC "переход_если_нет_переноса": {"opcode": b"\x0F\x83"}, # JNC "переход_если_ноль": {"opcode": b"\x0F\x84"}, # JZ "переход_если_не_ноль": {"opcode": b"\x0F\x85"}, # JNZ # Короткие условные переходы (8-битное смещение) "короткий_переход_если_равно": {"opcode": b"\x74"}, # JE SHORT "короткий_переход_если_неравно": {"opcode": b"\x75"}, # JNE SHORT "короткий_переход_если_меньше": {"opcode": b"\x7C"}, # JL SHORT "короткий_переход_если_больше": {"opcode": b"\x7F"}, # JG SHORT "короткий_переход_если_меньше_или_равно": {"opcode": b"\x7E"}, # JLE SHORT "короткий_переход_если_больше_или_равно": {"opcode": b"\x7D"}, # JGE SHORT "короткий_переход_если_перенос": {"opcode": b"\x72"}, # JC SHORT "короткий_переход_если_нет_переноса": {"opcode": b"\x73"}, # JNC SHORT "короткий_переход_если_ноль": {"opcode": b"\x74"}, # JZ SHORT "короткий_переход_если_не_ноль": {"opcode": b"\x75"}, # JNZ SHORT "вызвать": {"opcode": b"\xE8"}, # CALL rel32 "вернуться": {"opcode": b"\xC3"}, # RET # === Стековые инструкции === "втолкнуть": {"opcode": b"\x50", "reg_offset": 0}, # PUSH reg "вытолкнуть": {"opcode": b"\x58", "reg_offset": 0}, # POP reg "втолкнуть_непосредственно": {"opcode": b"\x68"}, # PUSH imm32 "втолкнуть_байт": {"opcode": b"\x6A"}, # PUSH imm8 # === Инструкции работы с битами === "сдвиг_влево": {"opcode": b"\x48\xC1\xE0", "type": "shift"}, # SHL reg, imm "сдвиг_вправо": {"opcode": b"\x48\xC1\xE8", "type": "shift"}, # SHR reg, imm "сдвиг_арифметический_вправо": {"opcode": b"\x48\xC1\xF8", "type": "shift"}, # SAR reg, imm "вращать_влево": {"opcode": b"\x48\xC1\xC0", "type": "rotate"}, # ROL reg, imm "вращать_вправо": {"opcode": b"\x48\xC1\xC8", "type": "rotate"}, # ROR reg, imm # === Инструкции управления потоком === "цикл": {"opcode": b"\xE2"}, # LOOP rel8 "обменять": {"opcode": b"\x48\x87"}, # XCHG reg, reg # === Системные инструкции === "вызов_системы": {"opcode": b"\x0F\x05"}, # SYSCALL "прервать": {"opcode": b"\xCD"}, # INT imm8 "войти_в_систему": {"opcode": b"\x0F\x34"}, # SYSENTER "остановить": {"opcode": b"\xF4"}, # HLT # === Отладочные инструкции === "нет_операции": {"opcode": b"\x90"}, # NOP "отладка": {"opcode": b"\xCC"}, # INT3 # === Строковые инструкции === "переместить_байт": {"opcode": b"\xA4"}, # MOVSB "переместить_слово": {"opcode": b"\xA5"}, # MOVSW "сравнить_байты": {"opcode": b"\xA6"}, # CMPSB "сканировать_байт": {"opcode": b"\xAE"}, # SCASB # === Инструкции работы с флагами === "установить_перенос": {"opcode": b"\xF9"}, # STC "сбросить_перенос": {"opcode": b"\xF8"}, # CLC "установить_направление": {"opcode": b"\xFD"}, # STD "сбросить_направление": {"opcode": b"\xFC"}, # CLD "втолкнуть_флаги": {"opcode": b"\x9C"}, # PUSHF "вытолкнуть_флаги": {"opcode": b"\x9D"}, # POPF # === Инструкции ввода-вывода === "ввод_байта": {"opcode": b"\xE4"}, # IN imm8 "вывод_байта": {"opcode": b"\xE6"}, # OUT imm8 # === Инструкции идентификации процессора === "идентифицировать_процессор": {"opcode": b"\x0F\xA2"}, # CPUID "прочитать_счётчик": {"opcode": b"\x0F\x31"}, # RDTSC } # === ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ === def get_reg_info(reg_name): """ Получает информацию о регистре по его имени. Возвращает словарь: - size: размер в битах (8, 16, 32, 64) - index: индекс регистра (0-15) - high8: True для старших байтов AH, CH, DH, BH Аргументы: reg_name (str): имя регистра (например, "раикс", "еаикс", "ал", "аш") Возвращает: dict: информация о регистре Пример: >>> get_reg_info("раикс") {'size': 64, 'index': 0} >>> get_reg_info("ал") {'size': 8, 'index': 0, 'high8': False} >>> get_reg_info("аш") {'size': 8, 'index': 0, 'high8': True} """ # Старшие 8-битные регистры (AH, CH, DH, BH) if reg_name in ["аш", "чш", "дш", "бш"]: return {"size": 8, "index": REGISTERS[reg_name], "high8": True} # Младшие 8-битные регистры (AL, CL, DL, BL, SPL, BPL, SIL, DIL, R8B-R15B) elif (reg_name.endswith(("б", "л")) or reg_name in ["ал", "кл", "дл", "бл", "спл", "бпл", "сил", "дил"]): return {"size": 8, "index": REGISTERS[reg_name], "high8": False} # 16-битные регистры (заканчиваются на "в" или имеют специальные имена) elif (reg_name.endswith("в") or reg_name in ["аикс", "сикс", "дикс", "бикс", "эсп", "бипи", "эс", "ди"]): return {"size": 16, "index": REGISTERS[reg_name]} # 32-битные регистры (заканчиваются на "д" или имеют специальные имена) elif (reg_name.endswith("д") or reg_name in ["еаикс", "есикс", "едикс", "ебикс", "есипи", "ебипи", "есиай", "едиай"]): return {"size": 32, "index": REGISTERS[reg_name]} # 64-битные регистры (все остальные) else: if reg_name not in REGISTERS: raise ValueError(f"Неизвестный регистр: {reg_name}") return {"size": 64, "index": REGISTERS[reg_name]} def align_up(x, align): """ Выравнивание числа вверх до указанной границы. Аргументы: x (int): исходное число align (int): граница выравнивания (степень двойки) Возвращает: int: выровненное вверх значение Пример: >>> align_up(100, 16) 112 >>> align_up(128, 16) 128 """ return (x + align - 1) & ~(align - 1)