маркеры секций

This commit is contained in:
mzhoot 2026-05-25 18:19:13 +03:00
parent 876e00a1ca
commit 99579d2538
4 changed files with 93 additions and 489 deletions

View file

@ -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)}")

View file

@ -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__":

View file

@ -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()

View file

@ -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()