маркеры секций
This commit is contained in:
parent
876e00a1ca
commit
99579d2538
55
kvs_pass1.py
55
kvs_pass1.py
|
|
@ -31,6 +31,7 @@ last_segment = None
|
|||
vaddr_text = text_vaddr_base
|
||||
vaddr_data = None
|
||||
vaddr_bnd = None
|
||||
data_offset = 0x2000 # начальное значение, будет пересчитано в finalize_headers
|
||||
|
||||
text_buffer = bytearray()
|
||||
data_buffer = bytearray()
|
||||
|
|
@ -64,6 +65,7 @@ def reset_state():
|
|||
bnd_size = 0
|
||||
vaddr_data = None
|
||||
vaddr_bnd = None
|
||||
data_offset = 0x2000 # добавить
|
||||
labels = {}
|
||||
label_sections = {}
|
||||
symbols = {}
|
||||
|
|
@ -81,12 +83,14 @@ def set_segment(segment: str):
|
|||
|
||||
def get_virtual_address():
|
||||
"""Возвращает виртуальный адрес для текущей позиции"""
|
||||
global data_offset # добавить
|
||||
|
||||
if current_segment == '.text':
|
||||
return vaddr_text + (current_address - 0x1000)
|
||||
elif current_segment == '.data':
|
||||
if vaddr_data is None:
|
||||
return current_address
|
||||
return vaddr_data + (current_address - 0x2000)
|
||||
return vaddr_data + (current_address - data_offset)
|
||||
else:
|
||||
return current_address
|
||||
|
||||
|
|
@ -100,7 +104,7 @@ def add_byte(value: int, source: str = "", target=None, labels_list=None):
|
|||
elif pending_labels:
|
||||
effective_labels = ','.join(pending_labels)
|
||||
|
||||
show_segment = current_segment if current_segment != last_segment else None
|
||||
show_segment = current_segment# if current_segment != last_segment else None
|
||||
if show_segment:
|
||||
last_segment = current_segment
|
||||
|
||||
|
|
@ -462,6 +466,11 @@ def process_ast_line(line):
|
|||
elif directive == '.данные':
|
||||
set_segment('.data')
|
||||
align_to(PAGE_SIZE)
|
||||
# Пересчитываем data_offset, так как .text уже полностью обработан
|
||||
global data_offset
|
||||
data_offset = align_up(0x1000 + text_pos, PAGE_SIZE)
|
||||
# Для отладки (можно убрать)
|
||||
print(f" .data: пересчитан data_offset = 0x{data_offset:x} (text_pos={text_pos})")
|
||||
|
||||
elif directive == '.бнд':
|
||||
set_segment('.bss')
|
||||
|
|
@ -642,14 +651,15 @@ def process_ast_line(line):
|
|||
|
||||
|
||||
def finalize_headers():
|
||||
global entries
|
||||
global entries, data_offset # добавить data_offset в global
|
||||
|
||||
text_offset = 0x1000
|
||||
data_offset = 0x2000
|
||||
|
||||
text_filesz = len(text_buffer)
|
||||
text_memsz = len(text_buffer)
|
||||
|
||||
# ВЫЧИСЛЯЕМ ФАЙЛОВОЕ СМЕЩЕНИЕ ДЛЯ DATA ДИНАМИЧЕСКИ
|
||||
data_offset = align_up(text_offset + text_filesz, PAGE_SIZE)
|
||||
|
||||
data_filesz = len(data_buffer)
|
||||
data_memsz = len(data_buffer) + bnd_size
|
||||
|
||||
|
|
@ -794,6 +804,37 @@ def save_to_csv(filename: str):
|
|||
])
|
||||
|
||||
|
||||
|
||||
def print_section_info():
|
||||
"""Выводит информацию о секциях с учётом выравнивания"""
|
||||
text_start_offset = 0x1000
|
||||
text_end_offset = text_start_offset + len(text_buffer)
|
||||
text_end_aligned = align_up(text_end_offset, PAGE_SIZE)
|
||||
|
||||
data_start_offset = text_end_aligned
|
||||
data_end_offset = data_start_offset + len(data_buffer)
|
||||
data_end_aligned = align_up(data_end_offset, PAGE_SIZE)
|
||||
|
||||
bnd_start_offset = data_end_aligned
|
||||
bnd_end_offset = bnd_start_offset + bnd_size
|
||||
|
||||
print(f"\n=== Информация о размещении секций (файловые смещения) ===")
|
||||
print(f" .text: {len(text_buffer)} байт, смещение 0x{text_start_offset:x} - 0x{text_end_offset-1:x}")
|
||||
print(f" выровнено: следующий сектор начнётся с 0x{text_end_aligned:x}")
|
||||
print(f" .data: {len(data_buffer)} байт, смещение 0x{data_start_offset:x} - 0x{data_end_offset-1:x}")
|
||||
print(f" выровнено: следующий сектор начнётся с 0x{data_end_aligned:x}")
|
||||
if bnd_size > 0:
|
||||
print(f" .bnd: {bnd_size} байт, смещение 0x{bnd_start_offset:x} - 0x{bnd_end_offset-1:x}")
|
||||
|
||||
print(f"\n=== Виртуальные адреса ===")
|
||||
print(f" .text: 0x{vaddr_text:x} - 0x{vaddr_text + len(text_buffer) - 1:x}")
|
||||
data_vaddr = align_up(vaddr_text + len(text_buffer), PAGE_SIZE)
|
||||
print(f" .data: 0x{data_vaddr:x} - 0x{data_vaddr + len(data_buffer) - 1:x}")
|
||||
if bnd_size > 0:
|
||||
bnd_vaddr = align_up(data_vaddr + len(data_buffer), PAGE_SIZE)
|
||||
print(f" .bnd: 0x{bnd_vaddr:x} - 0x{bnd_vaddr + bnd_size - 1:x}")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("Использование: python kvs_pass1.py <вход.аст> <выход.csv>")
|
||||
|
|
@ -815,13 +856,15 @@ def main():
|
|||
|
||||
finalize_headers()
|
||||
save_to_csv(csv_file)
|
||||
# Добавить эту строку:
|
||||
print_section_info()
|
||||
|
||||
vaddr_data_final = align_up(vaddr_text + len(text_buffer), PAGE_SIZE)
|
||||
vaddr_bnd_final = align_up(vaddr_data_final + len(data_buffer), PAGE_SIZE)
|
||||
|
||||
print(f"\n=== Первый проход ===")
|
||||
print(f" .text: {len(text_buffer)} байт, vaddr=0x{vaddr_text:x}")
|
||||
print(f" .data: {len(data_buffer)} байт, vaddr=0x{vaddr_data_final:x}")
|
||||
print(f" .data: {len(data_buffer)} байт, vaddr=0x{vaddr_data_final:x}, offset=0x{align_up(0x1000 + len(text_buffer), PAGE_SIZE):x}")
|
||||
print(f" .bnd: {bnd_size} байт, vaddr=0x{vaddr_bnd_final:x}")
|
||||
print(f" точка входа: {entry_point} = 0x{labels.get(entry_point, vaddr_text):x}")
|
||||
print(f" меток: {len(labels)}")
|
||||
|
|
|
|||
123
kvs_pass4.py
123
kvs_pass4.py
|
|
@ -53,7 +53,7 @@ def parse_command(cmd_str):
|
|||
return mnemonic, operands
|
||||
|
||||
|
||||
def detect_section_addresses(entries, headers):
|
||||
def detect_section_addresses(entries, headers, log_file):
|
||||
"""
|
||||
Определяет виртуальные адреса секций из CSV.
|
||||
"""
|
||||
|
|
@ -82,17 +82,17 @@ def detect_section_addresses(entries, headers):
|
|||
if segment == '.text' and not found_text:
|
||||
vaddr_text = virt_addr
|
||||
found_text = True
|
||||
print(f" .text: 0x{vaddr_text:x}")
|
||||
log_file.write(f" .text: 0x{vaddr_text:x}\n")
|
||||
|
||||
elif segment == '.data' and not found_data:
|
||||
vaddr_data = virt_addr
|
||||
found_data = True
|
||||
print(f" .data: 0x{vaddr_data:x}")
|
||||
log_file.write(f" .data: 0x{vaddr_data:x}\n")
|
||||
|
||||
elif segment == '.bss' and not found_bnd:
|
||||
vaddr_bnd = virt_addr
|
||||
found_bnd = True
|
||||
print(f" .bss: 0x{vaddr_bnd:x}")
|
||||
log_file.write(f" .bss: 0x{vaddr_bnd:x}\n")
|
||||
|
||||
# Проверяем, что все нужные секции найдены
|
||||
if not found_text:
|
||||
|
|
@ -100,11 +100,11 @@ def detect_section_addresses(entries, headers):
|
|||
sys.exit(1)
|
||||
|
||||
if not found_data:
|
||||
print(" Предупреждение: секция .data не найдена в CSV")
|
||||
log_file.write(" Предупреждение: секция .data не найдена в CSV, используем 0x402000\n")
|
||||
vaddr_data = 0x402000 # fallback
|
||||
|
||||
|
||||
def collect_labels_from_csv(entries, headers):
|
||||
def collect_labels_from_csv(entries, headers, log_file):
|
||||
"""
|
||||
Собирает метки из CSV, используя колонку 'виртуальный_адрес'
|
||||
"""
|
||||
|
|
@ -129,29 +129,11 @@ def collect_labels_from_csv(entries, headers):
|
|||
if label_name:
|
||||
labels[label_name] = virt_addr
|
||||
label_sections[label_name] = ''
|
||||
|
||||
|
||||
def get_section_for_address(virt_addr):
|
||||
"""
|
||||
Определяет секцию по виртуальному адресу
|
||||
"""
|
||||
if vaddr_text is not None and virt_addr >= vaddr_text:
|
||||
# Простая эвристика: если адрес в диапазоне .text (первые 0x1000 байт)
|
||||
if virt_addr < vaddr_text + PAGE_SIZE:
|
||||
return '.text'
|
||||
|
||||
if vaddr_data is not None and virt_addr >= vaddr_data:
|
||||
if virt_addr < vaddr_data + PAGE_SIZE:
|
||||
return '.data'
|
||||
|
||||
if vaddr_bnd is not None and virt_addr >= vaddr_bnd:
|
||||
if virt_addr < vaddr_bnd + PAGE_SIZE:
|
||||
return '.bss'
|
||||
|
||||
return '.unknown'
|
||||
log_file.write(f"Найдено меток: {len(labels)}\n")
|
||||
|
||||
|
||||
def reencode_instructions(entries, headers):
|
||||
def reencode_instructions(entries, headers, log_file):
|
||||
try:
|
||||
source_with_values_idx = headers.index('команда_со_значениями')
|
||||
calc_byte_idx = headers.index('рассчитанный_байт')
|
||||
|
|
@ -189,30 +171,12 @@ def reencode_instructions(entries, headers):
|
|||
try:
|
||||
mnemonic, operands = parse_command(cmd)
|
||||
if mnemonic:
|
||||
# ОТЛАДОЧНЫЙ ВЫВОД (только для переходов)
|
||||
if mnemonic.startswith('короткий_переход') or mnemonic.startswith('переход'):
|
||||
print(f"\n=== ОТЛАДКА ===")
|
||||
print(f" Адрес в CSV: 0x{file_addr:08x}")
|
||||
print(f" Виртуальный адрес инструкции: 0x{instr_virt_addr:08x}")
|
||||
print(f" Команда: {cmd}")
|
||||
print(f" Мнемоника: {mnemonic}")
|
||||
print(f" Операнды: {operands}")
|
||||
|
||||
if operands and len(operands) > 0:
|
||||
target_str = operands[0]
|
||||
if target_str.startswith('0x'):
|
||||
target_addr = int(target_str, 16)
|
||||
# Определяем размер инструкции
|
||||
if mnemonic.startswith('короткий'):
|
||||
instr_size = 2
|
||||
else:
|
||||
instr_size = 5
|
||||
offset = target_addr - (instr_virt_addr + instr_size)
|
||||
print(f" Целевой адрес: 0x{target_addr:08x}")
|
||||
print(f" Размер инструкции: {instr_size}")
|
||||
print(f" RIP = 0x{instr_virt_addr + instr_size:08x}")
|
||||
print(f" Смещение = {offset} (0x{offset & 0xFFFFFFFF:08x})")
|
||||
print(f" В диапазоне [-128..127]: {-128 <= offset <= 127}")
|
||||
# Для отладки: записываем в лог все инструкции переместить_имм
|
||||
if mnemonic == 'переместить_имм' and operands and '0x00403014' in cmd:
|
||||
log_file.write(f"\nDEBUG MOV:\n")
|
||||
log_file.write(f" Адрес в CSV: 0x{file_addr:08x}\n")
|
||||
log_file.write(f" Команда: {cmd}\n")
|
||||
log_file.write(f" Операнды: {operands}\n")
|
||||
|
||||
# Вычисляем current_pos как смещение в секции
|
||||
section = row[segment_idx].strip()
|
||||
|
|
@ -224,7 +188,7 @@ def reencode_instructions(entries, headers):
|
|||
elif section == '.bss':
|
||||
current_pos = instr_virt_addr - vaddr_bnd if vaddr_bnd else 0
|
||||
else:
|
||||
# Fallback: определяем по диапазону адресов
|
||||
# Fallback: определяем по диапазону адресов - ФУФЛО, УБРАТЬ
|
||||
if vaddr_text and 0x401000 <= instr_virt_addr < 0x402000:
|
||||
current_pos = instr_virt_addr - vaddr_text
|
||||
elif vaddr_data and 0x402000 <= instr_virt_addr < 0x403000:
|
||||
|
|
@ -238,9 +202,10 @@ def reencode_instructions(entries, headers):
|
|||
current_pos, vaddr_bnd if vaddr_bnd else 0
|
||||
)
|
||||
|
||||
if mnemonic.startswith('короткий_переход') or mnemonic.startswith('переход'):
|
||||
print(f" Закодировано: {[f'0x{b:02x}' for b in encoded]}")
|
||||
print(f" РЕЗУЛЬТАТ: УСПЕШНО")
|
||||
# Для отладки: записываем результат
|
||||
if mnemonic == 'переместить_имм' and operands and '0x00403014' in cmd:
|
||||
log_file.write(f" Закодировано: {[f'0x{b:02x}' for b in encoded]}\n")
|
||||
log_file.write(f" Длина: {len(encoded)} байт\n")
|
||||
|
||||
for j, byte in enumerate(encoded):
|
||||
if i + j < len(entries):
|
||||
|
|
@ -251,12 +216,10 @@ def reencode_instructions(entries, headers):
|
|||
continue
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n=== ОТЛАДКА (ОШИБКА) ===")
|
||||
print(f" Команда: {cmd}")
|
||||
print(f" Мнемоника: {mnemonic if 'mnemonic' in locals() else '?'}")
|
||||
print(f" Операнды: {operands if 'operands' in locals() else '?'}")
|
||||
print(f" Виртуальный адрес инструкции: 0x{instr_virt_addr:08x}")
|
||||
print(f" ОШИБКА: {e}")
|
||||
log_file.write(f"\n=== ОШИБКА ===\n")
|
||||
log_file.write(f" Команда: {cmd}\n")
|
||||
log_file.write(f" Мнемоника: {mnemonic if 'mnemonic' in locals() else '?'}\n")
|
||||
log_file.write(f" Ошибка: {e}\n")
|
||||
error_count += 1
|
||||
row[calc_byte_idx] = "0xcc"
|
||||
i += 1
|
||||
|
|
@ -293,34 +256,36 @@ def main():
|
|||
sys.exit(1)
|
||||
|
||||
csv_file = sys.argv[1]
|
||||
log_file_name = csv_file.replace('.csv', '_pass4.log')
|
||||
|
||||
print(f"\n=== Четвёртый проход КВС ===")
|
||||
print(f"Чтение CSV: {csv_file}")
|
||||
|
||||
headers, entries = read_csv(csv_file)
|
||||
|
||||
print(f"\n--- Определение адресов секций из CSV ---")
|
||||
detect_section_addresses(entries, headers)
|
||||
|
||||
print(f"\n--- Сбор меток из CSV ---")
|
||||
collect_labels_from_csv(entries, headers)
|
||||
print(f"Найдено меток: {len(labels)}")
|
||||
|
||||
if labels:
|
||||
print(f"\n--- Примеры меток (виртуальные адреса) ---")
|
||||
for i, name in enumerate(sorted(labels.keys())[:10]):
|
||||
print(f" {name} -> 0x{labels[name]:08x}")
|
||||
if len(labels) > 10:
|
||||
print(f" ... и ещё {len(labels) - 10}")
|
||||
|
||||
print(f"\n--- Перекодирование инструкций ---")
|
||||
reencoded_count, error_count = reencode_instructions(entries, headers)
|
||||
with open(log_file_name, 'w', encoding='utf-8') as log_file:
|
||||
log_file.write(f"=== Четвёртый проход КВС ===\n")
|
||||
log_file.write(f"CSV: {csv_file}\n\n")
|
||||
|
||||
headers, entries = read_csv(csv_file)
|
||||
|
||||
log_file.write(f"--- Определение адресов секций из CSV ---\n")
|
||||
detect_section_addresses(entries, headers, log_file)
|
||||
|
||||
log_file.write(f"\n--- Сбор меток из CSV ---\n")
|
||||
collect_labels_from_csv(entries, headers, log_file)
|
||||
|
||||
log_file.write(f"\n--- Перекодирование инструкций ---\n")
|
||||
reencoded_count, error_count = reencode_instructions(entries, headers, log_file)
|
||||
|
||||
log_file.write(f"\n--- Статистика ---\n")
|
||||
log_file.write(f" Меток в словаре: {len(labels)}\n")
|
||||
log_file.write(f" Перекодировано инструкций: {reencoded_count}\n")
|
||||
log_file.write(f" Ошибок: {error_count}\n")
|
||||
|
||||
print_statistics(reencoded_count, error_count, len(labels))
|
||||
|
||||
save_csv(csv_file, headers, entries)
|
||||
print(f"\nCSV сохранён: {csv_file}")
|
||||
print(f"Колонка 'рассчитанный_байт' обновлена")
|
||||
print(f"Лог сохранён: {log_file_name}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -1,237 +0,0 @@
|
|||
#!/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()
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
kvs_elf.py - Генерация ELF заголовков для КВС
|
||||
Содержит функции для создания ELF64 заголовка и программных заголовков
|
||||
"""
|
||||
|
||||
import struct
|
||||
from kvs_data import PAGE_SIZE, text_vaddr_base
|
||||
|
||||
|
||||
class ELFHeader:
|
||||
"""Генератор ELF64 заголовков"""
|
||||
|
||||
# ELF константы
|
||||
EI_MAG0 = 0x7F
|
||||
EI_MAG1 = ord('E')
|
||||
EI_MAG2 = ord('L')
|
||||
EI_MAG3 = ord('F')
|
||||
EI_CLASS64 = 2
|
||||
EI_DATA2LSB = 1
|
||||
EI_VERSION = 1
|
||||
ET_EXEC = 2
|
||||
EM_X86_64 = 62
|
||||
EV_CURRENT = 1
|
||||
PT_LOAD = 1
|
||||
PF_R = 0x4
|
||||
PF_W = 0x2
|
||||
PF_X = 0x1
|
||||
|
||||
def __init__(self):
|
||||
self.entry_point = 0 # будет заполнено позже
|
||||
|
||||
def get_header_bytes(self):
|
||||
"""Возвращает байты ELF заголовка"""
|
||||
# e_ident (16 байт)
|
||||
e_ident = bytes([
|
||||
self.EI_MAG0, self.EI_MAG1, self.EI_MAG2, self.EI_MAG3, # magic
|
||||
self.EI_CLASS64, # ELFCLASS64
|
||||
self.EI_DATA2LSB, # ELFDATA2LSB
|
||||
self.EI_VERSION, # EV_CURRENT
|
||||
0, # OS ABI (none)
|
||||
0, # ABI version
|
||||
0, 0, 0, 0, 0, 0, 0 # padding
|
||||
])
|
||||
|
||||
# Собираем заголовок
|
||||
header = bytearray(e_ident)
|
||||
header.extend(struct.pack('<H', self.ET_EXEC)) # e_type
|
||||
header.extend(struct.pack('<H', self.EM_X86_64)) # e_machine
|
||||
header.extend(struct.pack('<I', self.EV_CURRENT)) # e_version
|
||||
header.extend(struct.pack('<Q', self.entry_point)) # e_entry
|
||||
header.extend(struct.pack('<Q', 64)) # e_phoff (программные заголовки сразу после ELF)
|
||||
header.extend(struct.pack('<Q', 0)) # e_shoff (нет секций)
|
||||
header.extend(struct.pack('<I', 0)) # e_flags
|
||||
header.extend(struct.pack('<H', 64)) # e_ehsize
|
||||
header.extend(struct.pack('<H', 56)) # e_phentsize
|
||||
header.extend(struct.pack('<H', 2)) # e_phnum (2 программных заголовка)
|
||||
header.extend(struct.pack('<H', 0)) # e_shentsize
|
||||
header.extend(struct.pack('<H', 0)) # e_shnum
|
||||
header.extend(struct.pack('<H', 0)) # e_shstrndx
|
||||
|
||||
return bytes(header)
|
||||
|
||||
def set_entry_point(self, addr):
|
||||
"""Устанавливает точку входа"""
|
||||
self.entry_point = addr
|
||||
|
||||
|
||||
class ProgramHeaders:
|
||||
"""Генератор программных заголовков ELF"""
|
||||
|
||||
def __init__(self):
|
||||
self.text_offset = 0x1000
|
||||
self.text_vaddr = text_vaddr_base
|
||||
self.text_paddr = text_vaddr_base
|
||||
self.text_filesz = 0
|
||||
self.text_memsz = 0
|
||||
|
||||
self.data_offset = 0x2000
|
||||
self.data_vaddr = 0
|
||||
self.data_paddr = 0
|
||||
self.data_filesz = 0
|
||||
self.data_memsz = 0
|
||||
|
||||
def get_text_header_bytes(self):
|
||||
"""Возвращает байты программного заголовка для TEXT сегмента"""
|
||||
header = bytearray()
|
||||
header.extend(struct.pack('<I', ELFHeader.PT_LOAD)) # p_type
|
||||
header.extend(struct.pack('<I', ELFHeader.PF_R | ELFHeader.PF_X)) # p_flags = RX
|
||||
header.extend(struct.pack('<Q', self.text_offset)) # p_offset
|
||||
header.extend(struct.pack('<Q', self.text_vaddr)) # p_vaddr
|
||||
header.extend(struct.pack('<Q', self.text_paddr)) # p_paddr
|
||||
header.extend(struct.pack('<Q', self.text_filesz)) # p_filesz
|
||||
header.extend(struct.pack('<Q', self.text_memsz)) # p_memsz
|
||||
header.extend(struct.pack('<Q', PAGE_SIZE)) # p_align
|
||||
return bytes(header)
|
||||
|
||||
def get_data_header_bytes(self):
|
||||
"""Возвращает байты программного заголовка для DATA сегмента"""
|
||||
header = bytearray()
|
||||
header.extend(struct.pack('<I', ELFHeader.PT_LOAD)) # p_type
|
||||
header.extend(struct.pack('<I', ELFHeader.PF_R | ELFHeader.PF_W)) # p_flags = RW
|
||||
header.extend(struct.pack('<Q', self.data_offset)) # p_offset
|
||||
header.extend(struct.pack('<Q', self.data_vaddr)) # p_vaddr
|
||||
header.extend(struct.pack('<Q', self.data_paddr)) # p_paddr
|
||||
header.extend(struct.pack('<Q', self.data_filesz)) # p_filesz
|
||||
header.extend(struct.pack('<Q', self.data_memsz)) # p_memsz
|
||||
header.extend(struct.pack('<Q', PAGE_SIZE)) # p_align
|
||||
return bytes(header)
|
||||
|
||||
def set_text_sizes(self, filesz, memsz=None):
|
||||
"""Устанавливает размеры TEXT сегмента"""
|
||||
self.text_filesz = filesz
|
||||
self.text_memsz = memsz if memsz is not None else filesz
|
||||
|
||||
def set_data_sizes(self, filesz, memsz=None):
|
||||
"""Устанавливает размеры DATA сегмента"""
|
||||
self.data_filesz = filesz
|
||||
self.data_memsz = memsz if memsz is not None else filesz
|
||||
|
||||
def set_data_vaddr(self, vaddr):
|
||||
"""Устанавливает виртуальный адрес DATA сегмента"""
|
||||
self.data_vaddr = vaddr
|
||||
self.data_paddr = vaddr
|
||||
|
||||
|
||||
def generate_elf_bytes(entry_point, text_filesz, text_memsz, data_vaddr, data_filesz, data_memsz):
|
||||
"""
|
||||
Генерирует полный ELF заголовок (ELF header + 2 program headers)
|
||||
Возвращает bytes
|
||||
"""
|
||||
elf = ELFHeader()
|
||||
elf.set_entry_point(entry_point)
|
||||
|
||||
ph = ProgramHeaders()
|
||||
ph.set_text_sizes(text_filesz, text_memsz)
|
||||
ph.set_data_sizes(data_filesz, data_memsz)
|
||||
ph.set_data_vaddr(data_vaddr)
|
||||
|
||||
# Собираем всё вместе
|
||||
result = bytearray()
|
||||
result.extend(elf.get_header_bytes()) # 64 байта
|
||||
result.extend(ph.get_text_header_bytes()) # 56 байт
|
||||
result.extend(ph.get_data_header_bytes()) # 56 байт
|
||||
|
||||
return bytes(result)
|
||||
|
||||
|
||||
# Для обратной совместимости со старым кодом
|
||||
def get_elf_header_bytes():
|
||||
"""Возвращает ELF заголовок с заглушками (для первого прохода)"""
|
||||
elf = ELFHeader()
|
||||
return elf.get_header_bytes()
|
||||
|
||||
|
||||
def get_text_phdr_bytes():
|
||||
"""Возвращает программный заголовок TEXT с заглушками"""
|
||||
ph = ProgramHeaders()
|
||||
return ph.get_text_header_bytes()
|
||||
|
||||
|
||||
def get_data_phdr_bytes():
|
||||
"""Возвращает программный заголовок DATA с заглушками"""
|
||||
ph = ProgramHeaders()
|
||||
return ph.get_data_header_bytes()
|
||||
Loading…
Reference in a new issue