kvs/kvs_data.py
2026-05-17 11:23:51 +03:00

309 lines
18 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
kvs_data.py
Общие данные для КВС - ассемблера
Регистры, инструкции, константы и вспомогательные функции
"""
import struct
# === ГЛОБАЛЬНЫЕ КОНСТАНТЫ ===
# Константы для секции .бнд (аналог .bss)
SECTION_BND = '.бнд'
SECTION_BND_ELF = '.bss' # Имя секции в ELF-файле (стандарт Linux)
# ELF-константы для секции типа SHT_NOBITS
SHT_NOBITS = 8
SHF_WRITE = 0x1
SHF_ALLOC = 0x2
# 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, # R8D - младшие 32 бита R8
"р": 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, # R8W - младшие 16 бит R8
"р": 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)