kvs/инструменты/kvs_csv_builder.py

237 lines
8 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
"""
Генератор CSV-таблицы для программы на КВС (функциональная версия)
Экспериментальный однопроходный ассемблер - с корректными заглушками ELF
"""
import sys
import csv
from typing import List, Optional, Tuple
# Глобальное состояние
entries = [] # Список записей: (address, byte, target, source, segment)
current_address = 0
current_segment = '.header'
last_segment = None
relocations = [] # Список отложенных ссылок: (pos, label, type, source)
def reset_state():
"""Сбросить состояние генератора"""
global entries, current_address, current_segment, last_segment, relocations
entries = []
current_address = 0
current_segment = '.header'
last_segment = None
relocations = []
def set_segment(segment: str):
"""Переключить текущий сегмент"""
global current_segment
current_segment = segment
def add_byte(value: int, source: str = "", target: Optional[int] = None):
"""Добавить один байт"""
global current_address, last_segment
# Показываем сегмент только при смене
show_segment = current_segment if current_segment != last_segment else None
if show_segment:
last_segment = current_segment
entries.append((
current_address,
value & 0xFF,
target,
source,
show_segment
))
current_address += 1
def add_bytes(values: List[int], source: str = ""):
"""Добавить последовательность байтов"""
for v in values:
add_byte(v, source)
def add_word32(value: int, source: str = ""):
"""Добавить 32-битное слово (little-endian)"""
add_bytes([
(value >> 0) & 0xFF,
(value >> 8) & 0xFF,
(value >> 16) & 0xFF,
(value >> 24) & 0xFF,
], source)
def add_word64(value: int, source: str = ""):
"""Добавить 64-битное слово (little-endian)"""
add_bytes([
(value >> 0) & 0xFF,
(value >> 8) & 0xFF,
(value >> 16) & 0xFF,
(value >> 24) & 0xFF,
(value >> 32) & 0xFF,
(value >> 40) & 0xFF,
(value >> 48) & 0xFF,
(value >> 56) & 0xFF,
], source)
def align_to(alignment: int):
"""Выровнять адрес до границы (просто двигаем адрес)"""
global current_address
padding = (alignment - (current_address % alignment)) % alignment
current_address += padding
def add_relocation(pos: int, label: str, reloc_type: str, source: str = ""):
"""Запомнить место для отложенной подстановки"""
relocations.append((pos, label, reloc_type, source))
def generate_elf_header():
"""Сгенерировать корректный ELF заголовок с заглушками"""
# EI_MAGIC
add_bytes([0x7F, 0x45, 0x4C, 0x46], "ELF magic")
# ei_class: 64-bit (2)
add_byte(2, "ELFCLASS64")
# ei_data: little-endian (1)
add_byte(1, "ELFDATA2LSB")
# ei_version: 1
add_byte(1, "ELF version")
# ei_osabi: System V (0)
add_byte(0, "OS ABI")
# ei_abiversion: 0
add_byte(0, "ABI version")
# ei_pad: 7 байт паддинга
add_bytes([0] * 7, "Padding")
# e_type: ET_EXEC (2)
add_word32(2, "e_type = ET_EXEC")
# e_machine: EM_X86_64 (62)
add_word32(62, "e_machine = EM_X86_64")
# e_version: 1
add_word32(1, "e_version")
# e_entry: точка входа (заглушка 0x401000)
add_word64(0x401000, "e_entry (stub: _start)")
# e_phoff: смещение до program headers (64 байта)
add_word64(64, "e_phoff")
# e_shoff: смещение до section headers (0 = нет секций)
add_word64(0, "e_shoff = 0")
# e_flags: 0
add_word32(0, "e_flags")
# e_ehsize: размер ELF заголовка (64)
add_word32(64, "e_ehsize")
# e_phentsize: размер program header entry (56)
add_word32(56, "e_phentsize")
# e_phnum: количество program headers (2)
add_word32(2, "e_phnum = 2")
# e_shentsize: размер section header entry (0)
add_word32(0, "e_shentsize = 0")
# e_shnum: количество section headers (0)
add_word32(0, "e_shnum = 0")
# e_shstrndx: индекс секции строк (0)
add_word32(0, "e_shstrndx")
def generate_program_headers():
"""Сгенерировать program headers с корректными выравниваниями"""
# Смещения в файле (должны быть кратны 4096)
text_offset = 0x1000 # 4096
data_offset = 0x2000 # 8192
# Program Header 1: TEXT (RX)
add_word32(1, "p_type = PT_LOAD")
add_word32(5, "p_flags = RX")
add_word64(text_offset, "p_offset (text)")
add_word64(0x401000, "p_vaddr (text)")
add_word64(0x401000, "p_paddr (text)")
add_word64(0, "p_filesz (stub)") # Заглушка
add_word64(0, "p_memsz (stub)") # Заглушка
add_word64(0x1000, "p_align (4KB)")
# Program Header 2: DATA (RW)
add_word32(1, "p_type = PT_LOAD")
add_word32(6, "p_flags = RW")
add_word64(data_offset, "p_offset (data)")
add_word64(0x402000, "p_vaddr (data)")
add_word64(0x402000, "p_paddr (data)")
add_word64(0, "p_filesz (stub)") # Заглушка
add_word64(0, "p_memsz (stub)") # Заглушка
add_word64(0x1000, "p_align (4KB)")
def generate_empty_program():
"""Сгенерировать пустую программу с корректным ELF скелетом"""
reset_state()
# Генерируем заголовки
set_segment('.header')
generate_elf_header()
generate_program_headers()
# Выравнивание до .text секции
align_to(0x1000)
# .text секция
set_segment('.text')
add_byte(0xCC, ".text section start (INT3)")
# Выравнивание до .data секции
align_to(0x1000)
# .data секция
set_segment('.data')
add_byte(0x00, ".data section start")
# Вывод информации
print(f"\n=== Сгенерирован скелет программы ===", file=sys.stderr)
print(f"ELF заголовок: 64 байта", file=sys.stderr)
print(f"Program headers: 112 байт (2 * 56)", file=sys.stderr)
print(f".text: 1 байт по адресу 0x401000", file=sys.stderr)
print(f".data: 1 байт по адресу 0x402000", file=sys.stderr)
print(f"\nПроверка readelf:", file=sys.stderr)
print(f" e_phoff = 64 (0x40) - верно", file=sys.stderr)
print(f" p_offset(text) = 4096 (0x1000) - кратно p_align", file=sys.stderr)
print(f" p_offset(data) = 8192 (0x2000) - кратно p_align", file=sys.stderr)
def save_to_csv(filename: str):
"""Сохранить таблицу в CSV"""
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f, delimiter=';')
writer.writerow(['адрес', 'байт', 'целевой_адрес', 'исходная_команда', 'сегмент'])
for addr, byte, target, source, segment in entries:
writer.writerow([
f"0x{addr:08x}",
f"0x{byte:02x}",
f"0x{target:08x}" if target is not None else "",
source,
segment if segment else ""
])
print(f"CSV сохранен: {filename}", file=sys.stderr)
def main():
if len(sys.argv) < 2:
print("Usage: python3 kvs_csv_builder.py <output.csv>")
sys.exit(1)
generate_empty_program()
save_to_csv(sys.argv[1])
print("\nГотово!", file=sys.stderr)
if __name__ == "__main__":
main()