адресация в bss
This commit is contained in:
parent
a75dc24a61
commit
403b999d42
196
kvs_pass1.py
196
kvs_pass1.py
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import csv
|
import csv
|
||||||
import struct # <--- НОВЫЙ ИМПОРТ
|
import struct
|
||||||
|
|
||||||
sys.path.insert(0, '.')
|
sys.path.insert(0, '.')
|
||||||
from kvs_data import (
|
from kvs_data import (
|
||||||
|
|
@ -31,11 +31,11 @@ last_segment = None
|
||||||
vaddr_text = text_vaddr_base
|
vaddr_text = text_vaddr_base
|
||||||
vaddr_data = None
|
vaddr_data = None
|
||||||
vaddr_bnd = None
|
vaddr_bnd = None
|
||||||
data_offset = 0x2000 # начальное значение, будет пересчитано в finalize_headers
|
data_offset = 0x2000
|
||||||
|
|
||||||
text_buffer = bytearray()
|
text_buffer = bytearray()
|
||||||
data_buffer = bytearray()
|
data_buffer = bytearray()
|
||||||
bnd_size = 0
|
bss_size = 0
|
||||||
|
|
||||||
labels = {}
|
labels = {}
|
||||||
label_sections = {}
|
label_sections = {}
|
||||||
|
|
@ -52,7 +52,8 @@ relocations = []
|
||||||
|
|
||||||
def reset_state():
|
def reset_state():
|
||||||
global entries, current_address, current_segment, last_segment
|
global entries, current_address, current_segment, last_segment
|
||||||
global text_buffer, data_buffer, bnd_size, vaddr_data, vaddr_bnd
|
global text_buffer, data_buffer, bss_size
|
||||||
|
global vaddr_data, vaddr_bnd
|
||||||
global labels, label_sections, symbols, text_pos, data_pos, entry_point, relocations
|
global labels, label_sections, symbols, text_pos, data_pos, entry_point, relocations
|
||||||
global pending_labels
|
global pending_labels
|
||||||
|
|
||||||
|
|
@ -62,10 +63,10 @@ def reset_state():
|
||||||
last_segment = None
|
last_segment = None
|
||||||
text_buffer = bytearray()
|
text_buffer = bytearray()
|
||||||
data_buffer = bytearray()
|
data_buffer = bytearray()
|
||||||
bnd_size = 0
|
bss_size = 0
|
||||||
vaddr_data = None
|
vaddr_data = None
|
||||||
vaddr_bnd = None
|
vaddr_bnd = None
|
||||||
data_offset = 0x2000 # добавить
|
data_offset = 0x2000
|
||||||
labels = {}
|
labels = {}
|
||||||
label_sections = {}
|
label_sections = {}
|
||||||
symbols = {}
|
symbols = {}
|
||||||
|
|
@ -83,7 +84,7 @@ def set_segment(segment: str):
|
||||||
|
|
||||||
def get_virtual_address():
|
def get_virtual_address():
|
||||||
"""Возвращает виртуальный адрес для текущей позиции"""
|
"""Возвращает виртуальный адрес для текущей позиции"""
|
||||||
global data_offset # добавить
|
global data_offset
|
||||||
|
|
||||||
if current_segment == '.text':
|
if current_segment == '.text':
|
||||||
return vaddr_text + (current_address - 0x1000)
|
return vaddr_text + (current_address - 0x1000)
|
||||||
|
|
@ -104,7 +105,7 @@ def add_byte(value: int, source: str = "", target=None, labels_list=None):
|
||||||
elif pending_labels:
|
elif pending_labels:
|
||||||
effective_labels = ','.join(pending_labels)
|
effective_labels = ','.join(pending_labels)
|
||||||
|
|
||||||
show_segment = current_segment# if current_segment != last_segment else None
|
show_segment = current_segment
|
||||||
if show_segment:
|
if show_segment:
|
||||||
last_segment = current_segment
|
last_segment = current_segment
|
||||||
|
|
||||||
|
|
@ -129,36 +130,59 @@ def add_byte(value: int, source: str = "", target=None, labels_list=None):
|
||||||
pending_labels = []
|
pending_labels = []
|
||||||
|
|
||||||
|
|
||||||
|
def add_bss_entry(size: int, label: str = None):
|
||||||
|
"""Добавляет запись для BSS в CSV (БЕЗ увеличения файлового адреса)"""
|
||||||
|
global bss_size, vaddr_bnd
|
||||||
|
|
||||||
|
bss_start = bss_size
|
||||||
|
bss_size += size
|
||||||
|
|
||||||
|
bss_file_addr = "BSS"
|
||||||
|
|
||||||
|
for offset in range(size):
|
||||||
|
virt_addr = vaddr_bnd + bss_start + offset
|
||||||
|
label_name = label if offset == 0 and label else ""
|
||||||
|
|
||||||
|
# ПОРЯДОК ПОЛЕЙ ДОЛЖЕН СООТВЕТСТВОВАТЬ РАСПАКОВКЕ В save_to_csv:
|
||||||
|
# segment, addr, virt_addr, byte_str, target, source, label, cmd_with_values, calc_target, calc_byte
|
||||||
|
entries.append((
|
||||||
|
".bss", # segment
|
||||||
|
bss_file_addr, # addr
|
||||||
|
f"0x{virt_addr:08x}", # virt_addr
|
||||||
|
"0x00", # byte_str
|
||||||
|
"", # target (уводящий_адрес) - пусто
|
||||||
|
f".резб {size}" if offset == 0 else "", # source (исходная_команда)
|
||||||
|
label_name, # label (приводящая_метка) ← сюда имя метки!
|
||||||
|
"", # cmd_with_values
|
||||||
|
"", # calc_target
|
||||||
|
"0x00" # calc_byte
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_bytes(values, source: str = "", target=None):
|
def add_bytes(values, source: str = "", target=None):
|
||||||
for i, v in enumerate(values):
|
for i, v in enumerate(values):
|
||||||
add_byte(v, source if i == 0 else "", target if i == 0 else None)
|
add_byte(v, source if i == 0 else "", target if i == 0 else None)
|
||||||
|
|
||||||
|
|
||||||
# ========== РЕФАКТОРИНГ: ИСПОЛЬЗУЕМ struct.pack ==========
|
|
||||||
|
|
||||||
def add_word16(value: int, source: str = "", target=None):
|
def add_word16(value: int, source: str = "", target=None):
|
||||||
"""Добавляет 16-битное значение (little-endian)"""
|
|
||||||
add_bytes(struct.pack('<H', value & 0xFFFF), source, target)
|
add_bytes(struct.pack('<H', value & 0xFFFF), source, target)
|
||||||
|
|
||||||
|
|
||||||
def add_word32(value: int, source: str = "", target=None):
|
def add_word32(value: int, source: str = "", target=None):
|
||||||
"""Добавляет 32-битное значение (little-endian)"""
|
|
||||||
add_bytes(struct.pack('<I', value & 0xFFFFFFFF), source, target)
|
add_bytes(struct.pack('<I', value & 0xFFFFFFFF), source, target)
|
||||||
|
|
||||||
|
|
||||||
def add_word64(value: int, source: str = "", target=None):
|
def add_word64(value: int, source: str = "", target=None):
|
||||||
"""Добавляет 64-битное значение (little-endian)"""
|
|
||||||
add_bytes(struct.pack('<Q', value & 0xFFFFFFFFFFFFFFFF), source, target)
|
add_bytes(struct.pack('<Q', value & 0xFFFFFFFFFFFFFFFF), source, target)
|
||||||
|
|
||||||
|
|
||||||
def add_dwords(values: list, source: str = "", target=None):
|
def add_dwords(values: list, source: str = "", target=None):
|
||||||
"""Добавляет несколько 32-битных значений"""
|
|
||||||
for val in values:
|
for val in values:
|
||||||
add_word32(val, source, target)
|
add_word32(val, source, target)
|
||||||
|
|
||||||
|
|
||||||
def add_qwords(values: list, source: str = "", target=None):
|
def add_qwords(values: list, source: str = "", target=None):
|
||||||
"""Добавляет несколько 64-битных значений"""
|
|
||||||
for val in values:
|
for val in values:
|
||||||
add_word64(val, source, target)
|
add_word64(val, source, target)
|
||||||
|
|
||||||
|
|
@ -192,8 +216,6 @@ def unescape_string(s):
|
||||||
|
|
||||||
|
|
||||||
def generate_elf_header():
|
def generate_elf_header():
|
||||||
"""Генерирует заголовок ELF (64 байта)"""
|
|
||||||
# ELF magic
|
|
||||||
add_bytes([0x7F, 0x45, 0x4C, 0x46], "ELF magic")
|
add_bytes([0x7F, 0x45, 0x4C, 0x46], "ELF magic")
|
||||||
add_byte(2, "ELFCLASS64")
|
add_byte(2, "ELFCLASS64")
|
||||||
add_byte(1, "ELFDATA2LSB")
|
add_byte(1, "ELFDATA2LSB")
|
||||||
|
|
@ -202,24 +224,19 @@ def generate_elf_header():
|
||||||
add_byte(0, "ABI version")
|
add_byte(0, "ABI version")
|
||||||
add_bytes([0] * 7, "Padding")
|
add_bytes([0] * 7, "Padding")
|
||||||
|
|
||||||
# e_type, e_machine, e_version
|
|
||||||
add_word16(2, "e_type = ET_EXEC")
|
add_word16(2, "e_type = ET_EXEC")
|
||||||
add_word16(62, "e_machine = EM_X86_64")
|
add_word16(62, "e_machine = EM_X86_64")
|
||||||
add_word32(1, "e_version")
|
add_word32(1, "e_version")
|
||||||
|
|
||||||
# e_entry (stub - будет заполнен позже)
|
|
||||||
add_word64(0, "e_entry (stub)")
|
add_word64(0, "e_entry (stub)")
|
||||||
|
|
||||||
# e_phoff, e_shoff
|
|
||||||
add_word64(64, "e_phoff")
|
add_word64(64, "e_phoff")
|
||||||
add_word64(0, "e_shoff = 0")
|
add_word64(0, "e_shoff = 0")
|
||||||
|
|
||||||
# e_flags, e_ehsize, e_phentsize
|
|
||||||
add_word32(0, "e_flags")
|
add_word32(0, "e_flags")
|
||||||
add_word16(64, "e_ehsize")
|
add_word16(64, "e_ehsize")
|
||||||
add_word16(56, "e_phentsize")
|
add_word16(56, "e_phentsize")
|
||||||
|
|
||||||
# e_phnum, e_shentsize, e_shnum, e_shstrndx
|
|
||||||
add_word16(2, "e_phnum = 2")
|
add_word16(2, "e_phnum = 2")
|
||||||
add_word16(0, "e_shentsize = 0")
|
add_word16(0, "e_shentsize = 0")
|
||||||
add_word16(0, "e_shnum = 0")
|
add_word16(0, "e_shnum = 0")
|
||||||
|
|
@ -227,25 +244,22 @@ def generate_elf_header():
|
||||||
|
|
||||||
|
|
||||||
def generate_program_headers():
|
def generate_program_headers():
|
||||||
"""Генерирует два программных заголовка (PT_LOAD)"""
|
|
||||||
# === Первый заголовок: TEXT (RX) ===
|
|
||||||
add_word32(1, "p_type = PT_LOAD")
|
add_word32(1, "p_type = PT_LOAD")
|
||||||
add_word32(5, "p_flags = RX")
|
add_word32(5, "p_flags = RX")
|
||||||
add_word64(0, "p_offset (text stub)") # будет заполнено позже
|
add_word64(0, "p_offset (text stub)")
|
||||||
add_word64(vaddr_text, "p_vaddr (text)")
|
add_word64(vaddr_text, "p_vaddr (text)")
|
||||||
add_word64(vaddr_text, "p_paddr (text)")
|
add_word64(vaddr_text, "p_paddr (text)")
|
||||||
add_word64(0, "p_filesz (text stub)") # будет заполнено позже
|
add_word64(0, "p_filesz (text stub)")
|
||||||
add_word64(0, "p_memsz (text stub)") # будет заполнено позже
|
add_word64(0, "p_memsz (text stub)")
|
||||||
add_word64(PAGE_SIZE, "p_align")
|
add_word64(PAGE_SIZE, "p_align")
|
||||||
|
|
||||||
# === Второй заголовок: DATA (RW) ===
|
|
||||||
add_word32(1, "p_type = PT_LOAD")
|
add_word32(1, "p_type = PT_LOAD")
|
||||||
add_word32(6, "p_flags = RW")
|
add_word32(6, "p_flags = RW")
|
||||||
add_word64(0, "p_offset (data stub)") # будет заполнено позже
|
add_word64(0, "p_offset (data stub)")
|
||||||
add_word64(0, "p_vaddr (data stub)") # будет заполнено позже
|
add_word64(0, "p_vaddr (data stub)")
|
||||||
add_word64(0, "p_paddr (data stub)") # будет заполнено позже
|
add_word64(0, "p_paddr (data stub)")
|
||||||
add_word64(0, "p_filesz (data stub)") # будет заполнено позже
|
add_word64(0, "p_filesz (data stub)")
|
||||||
add_word64(0, "p_memsz (data stub)") # будет заполнено позже
|
add_word64(0, "p_memsz (data stub)")
|
||||||
add_word64(PAGE_SIZE, "p_align")
|
add_word64(PAGE_SIZE, "p_align")
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -356,30 +370,24 @@ def get_stub_size(mnemonic, operands):
|
||||||
|
|
||||||
|
|
||||||
def extract_label_from_operands(operands):
|
def extract_label_from_operands(operands):
|
||||||
"""Извлекает первую метку из операндов инструкции"""
|
|
||||||
for op in operands:
|
for op in operands:
|
||||||
if not op:
|
if not op:
|
||||||
continue
|
continue
|
||||||
# Пропускаем регистры
|
|
||||||
if op in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
if op in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||||
'еаикс', 'ебикс', 'есикс', 'едикс',
|
'еаикс', 'ебикс', 'есикс', 'едикс',
|
||||||
'аикс', 'бикс', 'сикс', 'дикс',
|
'аикс', 'бикс', 'сикс', 'дикс',
|
||||||
'ал', 'бл', 'кл', 'дл',
|
'ал', 'бл', 'кл', 'дл',
|
||||||
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'):
|
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'):
|
||||||
continue
|
continue
|
||||||
# Пропускаем числа
|
|
||||||
if op.isdigit() or (op.startswith('0x') and len(op) > 2):
|
if op.isdigit() or (op.startswith('0x') and len(op) > 2):
|
||||||
continue
|
continue
|
||||||
# Пропускаем косвенную адресацию через регистр
|
|
||||||
if op.startswith('MEM:reg_indirect:'):
|
if op.startswith('MEM:reg_indirect:'):
|
||||||
continue
|
continue
|
||||||
# Извлекаем метку из [метка]
|
|
||||||
if op.startswith('[') and op.endswith(']'):
|
if op.startswith('[') and op.endswith(']'):
|
||||||
inner = op[1:-1]
|
inner = op[1:-1]
|
||||||
if inner not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай'):
|
if inner not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай'):
|
||||||
if not inner.isdigit() and not inner.startswith('0x'):
|
if not inner.isdigit() and not inner.startswith('0x'):
|
||||||
return inner
|
return inner
|
||||||
# Обычная метка
|
|
||||||
elif op not in symbols:
|
elif op not in symbols:
|
||||||
return op
|
return op
|
||||||
return None
|
return None
|
||||||
|
|
@ -452,7 +460,7 @@ def get_unresolved_labels(operands):
|
||||||
|
|
||||||
|
|
||||||
def process_ast_line(line):
|
def process_ast_line(line):
|
||||||
global text_pos, data_pos, vaddr_data, vaddr_bnd, bnd_size
|
global text_pos, data_pos, vaddr_data, vaddr_bnd, bss_size
|
||||||
global text_buffer, data_buffer, entry_point, symbols, pending_labels
|
global text_buffer, data_buffer, entry_point, symbols, pending_labels
|
||||||
|
|
||||||
line_type, fields = parse_ast_line(line)
|
line_type, fields = parse_ast_line(line)
|
||||||
|
|
@ -466,14 +474,16 @@ def process_ast_line(line):
|
||||||
elif directive == '.данные':
|
elif directive == '.данные':
|
||||||
set_segment('.data')
|
set_segment('.data')
|
||||||
align_to(PAGE_SIZE)
|
align_to(PAGE_SIZE)
|
||||||
# Пересчитываем data_offset, так как .text уже полностью обработан
|
|
||||||
global data_offset
|
global data_offset
|
||||||
data_offset = align_up(0x1000 + text_pos, PAGE_SIZE)
|
data_offset = align_up(0x1000 + text_pos, PAGE_SIZE)
|
||||||
# Для отладки (можно убрать)
|
|
||||||
print(f" .data: пересчитан data_offset = 0x{data_offset:x} (text_pos={text_pos})")
|
print(f" .data: пересчитан data_offset = 0x{data_offset:x} (text_pos={text_pos})")
|
||||||
|
|
||||||
elif directive == '.бнд':
|
elif directive == '.бнд':
|
||||||
set_segment('.bss')
|
set_segment('.bss')
|
||||||
|
# Инициализируем vaddr_bnd когда входим в BSS
|
||||||
|
if vaddr_bnd is None:
|
||||||
|
data_vaddr = vaddr_data if vaddr_data else align_up(vaddr_text + text_pos, PAGE_SIZE)
|
||||||
|
vaddr_bnd = align_up(data_vaddr + data_pos, PAGE_SIZE)
|
||||||
|
|
||||||
elif directive == '.глобал':
|
elif directive == '.глобал':
|
||||||
entry_point = fields.get('label', '_start')
|
entry_point = fields.get('label', '_start')
|
||||||
|
|
@ -530,7 +540,14 @@ def process_ast_line(line):
|
||||||
elif directive in ('.резб', '.резс', '.рездс', '.резкс'):
|
elif directive in ('.резб', '.резс', '.рездс', '.резкс'):
|
||||||
count = int(fields.get('count', '0'))
|
count = int(fields.get('count', '0'))
|
||||||
multiplier = {'резб': 1, 'резс': 2, 'рездс': 4, 'резкс': 8}
|
multiplier = {'резб': 1, 'резс': 2, 'рездс': 4, 'резкс': 8}
|
||||||
bnd_size += count * multiplier.get(directive, 1)
|
size = count * multiplier.get(directive, 1)
|
||||||
|
|
||||||
|
# Добавляем BSS в CSV
|
||||||
|
label_name = pending_labels[0] if pending_labels else None
|
||||||
|
add_bss_entry(size, label_name)
|
||||||
|
|
||||||
|
if label_name and pending_labels:
|
||||||
|
pending_labels = []
|
||||||
|
|
||||||
elif line_type == "LABEL":
|
elif line_type == "LABEL":
|
||||||
label_name = fields.get('name', '')
|
label_name = fields.get('name', '')
|
||||||
|
|
@ -554,8 +571,9 @@ def process_ast_line(line):
|
||||||
|
|
||||||
elif sec == '.бнд':
|
elif sec == '.бнд':
|
||||||
if vaddr_bnd is None:
|
if vaddr_bnd is None:
|
||||||
vaddr_bnd = align_up(vaddr_data + data_pos, PAGE_SIZE)
|
data_vaddr = vaddr_data if vaddr_data else align_up(vaddr_text + text_pos, PAGE_SIZE)
|
||||||
addr = vaddr_bnd + bnd_size
|
vaddr_bnd = align_up(data_vaddr + data_pos, PAGE_SIZE)
|
||||||
|
addr = vaddr_bnd + bss_size
|
||||||
labels[label_name] = addr
|
labels[label_name] = addr
|
||||||
label_sections[label_name] = sec
|
label_sections[label_name] = sec
|
||||||
if label_name not in pending_labels:
|
if label_name not in pending_labels:
|
||||||
|
|
@ -651,27 +669,62 @@ def process_ast_line(line):
|
||||||
|
|
||||||
|
|
||||||
def finalize_headers():
|
def finalize_headers():
|
||||||
global entries, data_offset # добавить data_offset в global
|
global entries, data_offset, vaddr_data, vaddr_bnd
|
||||||
|
|
||||||
|
print("\n[DEBUG finalize_headers] Начало")
|
||||||
|
|
||||||
text_offset = 0x1000
|
text_offset = 0x1000
|
||||||
text_filesz = len(text_buffer)
|
text_filesz = len(text_buffer)
|
||||||
text_memsz = len(text_buffer)
|
text_memsz = len(text_buffer)
|
||||||
|
|
||||||
# ВЫЧИСЛЯЕМ ФАЙЛОВОЕ СМЕЩЕНИЕ ДЛЯ DATA ДИНАМИЧЕСКИ
|
# Выравнивание для начала секции данных
|
||||||
data_offset = align_up(text_offset + text_filesz, PAGE_SIZE)
|
data_offset = align_up(text_offset + text_filesz, PAGE_SIZE)
|
||||||
|
print(f"[DEBUG] text_filesz={text_filesz}, data_offset=0x{data_offset:x}")
|
||||||
|
|
||||||
data_filesz = len(data_buffer)
|
data_filesz = len(data_buffer)
|
||||||
data_memsz = len(data_buffer) + bnd_size
|
|
||||||
|
|
||||||
vaddr_data_final = align_up(vaddr_text + text_filesz, PAGE_SIZE)
|
# Вычисляем виртуальные адреса с учётом выравнивания на PAGE_SIZE
|
||||||
|
vaddr_data_start = align_up(vaddr_text + text_filesz, PAGE_SIZE)
|
||||||
|
vaddr_bss_start = align_up(vaddr_data_start + data_filesz, PAGE_SIZE)
|
||||||
|
|
||||||
|
# Сохраняем в глобальные переменные
|
||||||
|
vaddr_data = vaddr_data_start
|
||||||
|
vaddr_bnd = vaddr_bss_start
|
||||||
|
|
||||||
|
# memsz должен покрывать всё: от начала .data до конца .bss
|
||||||
|
# Важно: включаем выравнивание между .data и .bss!
|
||||||
|
data_memsz = (vaddr_bss_start + bss_size) - vaddr_data_start
|
||||||
|
|
||||||
|
print(f"[DEBUG] vaddr_data_start=0x{vaddr_data_start:x}")
|
||||||
|
print(f"[DEBUG] vaddr_bss_start=0x{vaddr_bss_start:x}")
|
||||||
|
print(f"[DEBUG] data_filesz={data_filesz}, bss_size={bss_size}")
|
||||||
|
print(f"[DEBUG] data_memsz={data_memsz} (файл: {data_filesz}, память: {data_memsz})")
|
||||||
|
|
||||||
|
# Обновляем виртуальные адреса для BSS записей в CSV
|
||||||
|
for i, entry in enumerate(entries):
|
||||||
|
if entry[0] == ".bss" and entry[1] == "BSS":
|
||||||
|
old_virt = int(entry[2], 16)
|
||||||
|
# Вычисляем смещение внутри BSS
|
||||||
|
bss_offset = old_virt - vaddr_bss_start if vaddr_bss_start else 0
|
||||||
|
new_virt = vaddr_bss_start + bss_offset
|
||||||
|
entries[i] = (entry[0], entry[1], f"0x{new_virt:08x}", entry[3],
|
||||||
|
entry[4], entry[5], entry[6], entry[7], entry[8], entry[9])
|
||||||
|
print(f"[DEBUG] BSS запись: virt 0x{old_virt:x} -> 0x{new_virt:x}")
|
||||||
|
|
||||||
entry_point_addr = labels.get(entry_point, vaddr_text)
|
entry_point_addr = labels.get(entry_point, vaddr_text)
|
||||||
|
print(f"[DEBUG] entry_point_addr=0x{entry_point_addr:x}")
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(entries):
|
while i < len(entries):
|
||||||
segment, addr, virt_addr, byte_str, target, source, label, cmd_with_values, calc_target, calc_byte = entries[i]
|
segment, addr, virt_addr, byte_str, target, source, label, cmd_with_values, calc_target, calc_byte = entries[i]
|
||||||
|
|
||||||
|
# Пропускаем BSS-записи (они уже обработаны выше)
|
||||||
|
if segment == ".bss":
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Заполнение точки входа
|
||||||
if 'e_entry (stub)' in source:
|
if 'e_entry (stub)' in source:
|
||||||
# Вставляем 8 байт (uint64_t)
|
|
||||||
new_bytes = struct.pack('<Q', entry_point_addr)
|
new_bytes = struct.pack('<Q', entry_point_addr)
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
virt = f"0x{entry_point_addr + j:08x}"
|
virt = f"0x{entry_point_addr + j:08x}"
|
||||||
|
|
@ -683,6 +736,7 @@ def finalize_headers():
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Заполнение смещения текстовой секции
|
||||||
elif 'p_offset (text stub)' in source:
|
elif 'p_offset (text stub)' in source:
|
||||||
new_bytes = struct.pack('<Q', text_offset)
|
new_bytes = struct.pack('<Q', text_offset)
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
|
|
@ -695,6 +749,7 @@ def finalize_headers():
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Заполнение размера текстовой секции в файле
|
||||||
elif 'p_filesz (text stub)' in source:
|
elif 'p_filesz (text stub)' in source:
|
||||||
new_bytes = struct.pack('<Q', text_filesz)
|
new_bytes = struct.pack('<Q', text_filesz)
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
|
|
@ -707,6 +762,7 @@ def finalize_headers():
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Заполнение размера текстовой секции в памяти
|
||||||
elif 'p_memsz (text stub)' in source:
|
elif 'p_memsz (text stub)' in source:
|
||||||
new_bytes = struct.pack('<Q', text_memsz)
|
new_bytes = struct.pack('<Q', text_memsz)
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
|
|
@ -719,6 +775,7 @@ def finalize_headers():
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Заполнение смещения секции данных
|
||||||
elif 'p_offset (data stub)' in source:
|
elif 'p_offset (data stub)' in source:
|
||||||
new_bytes = struct.pack('<Q', data_offset)
|
new_bytes = struct.pack('<Q', data_offset)
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
|
|
@ -731,30 +788,33 @@ def finalize_headers():
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Заполнение виртуального адреса секции данных
|
||||||
elif 'p_vaddr (data stub)' in source:
|
elif 'p_vaddr (data stub)' in source:
|
||||||
new_bytes = struct.pack('<Q', vaddr_data_final)
|
new_bytes = struct.pack('<Q', vaddr_data_start)
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
virt = f"0x{vaddr_data_final + j:08x}"
|
virt = f"0x{vaddr_data_start + j:08x}"
|
||||||
byte_hex = f"0x{nb:02x}"
|
byte_hex = f"0x{nb:02x}"
|
||||||
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"p_vaddr (data) = 0x{vaddr_data_final:x}",
|
f"p_vaddr (data) = 0x{vaddr_data_start:x}",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "", byte_hex)
|
"", "", byte_hex)
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Заполнение физического адреса секции данных
|
||||||
elif 'p_paddr (data stub)' in source:
|
elif 'p_paddr (data stub)' in source:
|
||||||
new_bytes = struct.pack('<Q', vaddr_data_final)
|
new_bytes = struct.pack('<Q', vaddr_data_start)
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
virt = f"0x{vaddr_data_final + j:08x}"
|
virt = f"0x{vaddr_data_start + j:08x}"
|
||||||
byte_hex = f"0x{nb:02x}"
|
byte_hex = f"0x{nb:02x}"
|
||||||
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"p_paddr (data) = 0x{vaddr_data_final:x}",
|
f"p_paddr (data) = 0x{vaddr_data_start:x}",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "", byte_hex)
|
"", "", byte_hex)
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Заполнение размера секции данных в файле
|
||||||
elif 'p_filesz (data stub)' in source:
|
elif 'p_filesz (data stub)' in source:
|
||||||
new_bytes = struct.pack('<Q', data_filesz)
|
new_bytes = struct.pack('<Q', data_filesz)
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
|
|
@ -767,20 +827,22 @@ def finalize_headers():
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Заполнение размера секции данных в памяти (ВКЛЮЧАЯ BSS И ВЫРАВНИВАНИЕ!)
|
||||||
elif 'p_memsz (data stub)' in source:
|
elif 'p_memsz (data stub)' in source:
|
||||||
new_bytes = struct.pack('<Q', data_memsz)
|
new_bytes = struct.pack('<Q', data_memsz)
|
||||||
for j, nb in enumerate(new_bytes):
|
for j, nb in enumerate(new_bytes):
|
||||||
virt = f"0x{addr + j:08x}"
|
virt = f"0x{addr + j:08x}"
|
||||||
byte_hex = f"0x{nb:02x}"
|
byte_hex = f"0x{nb:02x}"
|
||||||
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
f"p_memsz (data) = {data_memsz}",
|
f"p_memsz (data) = {data_memsz} (data: {data_filesz}, bss: {bss_size}, выравнивание: {data_memsz - data_filesz - bss_size})",
|
||||||
label if j == 0 else "",
|
label if j == 0 else "",
|
||||||
"", "", byte_hex)
|
"", "", byte_hex)
|
||||||
i += 8
|
i += 8
|
||||||
continue
|
continue
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
print("[DEBUG finalize_headers] Завершено")
|
||||||
|
|
||||||
def save_to_csv(filename: str):
|
def save_to_csv(filename: str):
|
||||||
with open(filename, 'w', newline='', encoding='utf-8') as f:
|
with open(filename, 'w', newline='', encoding='utf-8') as f:
|
||||||
|
|
@ -792,7 +854,7 @@ def save_to_csv(filename: str):
|
||||||
for segment, addr, virt_addr, byte_str, target, source, label, cmd_with_values, calc_target, calc_byte in entries:
|
for segment, addr, virt_addr, byte_str, target, source, label, cmd_with_values, calc_target, calc_byte in entries:
|
||||||
writer.writerow([
|
writer.writerow([
|
||||||
segment,
|
segment,
|
||||||
f"0x{addr:08x}",
|
f"0x{addr:08x}" if isinstance(addr, int) else addr,
|
||||||
virt_addr,
|
virt_addr,
|
||||||
byte_str,
|
byte_str,
|
||||||
label,
|
label,
|
||||||
|
|
@ -804,9 +866,7 @@ def save_to_csv(filename: str):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def print_section_info():
|
def print_section_info():
|
||||||
"""Выводит информацию о секциях с учётом выравнивания"""
|
|
||||||
text_start_offset = 0x1000
|
text_start_offset = 0x1000
|
||||||
text_end_offset = text_start_offset + len(text_buffer)
|
text_end_offset = text_start_offset + len(text_buffer)
|
||||||
text_end_aligned = align_up(text_end_offset, PAGE_SIZE)
|
text_end_aligned = align_up(text_end_offset, PAGE_SIZE)
|
||||||
|
|
@ -815,24 +875,21 @@ def print_section_info():
|
||||||
data_end_offset = data_start_offset + len(data_buffer)
|
data_end_offset = data_start_offset + len(data_buffer)
|
||||||
data_end_aligned = align_up(data_end_offset, PAGE_SIZE)
|
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"\n=== Информация о размещении секций (файловые смещения) ===")
|
||||||
print(f" .text: {len(text_buffer)} байт, смещение 0x{text_start_offset:x} - 0x{text_end_offset-1:x}")
|
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" выровнено: следующий сектор начнётся с 0x{text_end_aligned:x}")
|
||||||
print(f" .data: {len(data_buffer)} байт, смещение 0x{data_start_offset:x} - 0x{data_end_offset-1: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}")
|
print(f" выровнено: следующий сектор начнётся с 0x{data_end_aligned:x}")
|
||||||
if bnd_size > 0:
|
if bss_size > 0:
|
||||||
print(f" .bnd: {bnd_size} байт, смещение 0x{bnd_start_offset:x} - 0x{bnd_end_offset-1:x}")
|
print(f" .bnd: {bss_size} байт (только в памяти, не в файле)")
|
||||||
|
|
||||||
print(f"\n=== Виртуальные адреса ===")
|
print(f"\n=== Виртуальные адреса ===")
|
||||||
print(f" .text: 0x{vaddr_text:x} - 0x{vaddr_text + len(text_buffer) - 1:x}")
|
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)
|
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}")
|
print(f" .data: 0x{data_vaddr:x} - 0x{data_vaddr + len(data_buffer) - 1:x}")
|
||||||
if bnd_size > 0:
|
if bss_size > 0:
|
||||||
bnd_vaddr = align_up(data_vaddr + len(data_buffer), PAGE_SIZE)
|
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}")
|
print(f" .bnd: 0x{bnd_vaddr:x} - 0x{bnd_vaddr + bss_size - 1:x}")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
@ -856,7 +913,6 @@ def main():
|
||||||
|
|
||||||
finalize_headers()
|
finalize_headers()
|
||||||
save_to_csv(csv_file)
|
save_to_csv(csv_file)
|
||||||
# Добавить эту строку:
|
|
||||||
print_section_info()
|
print_section_info()
|
||||||
|
|
||||||
vaddr_data_final = align_up(vaddr_text + len(text_buffer), PAGE_SIZE)
|
vaddr_data_final = align_up(vaddr_text + len(text_buffer), PAGE_SIZE)
|
||||||
|
|
@ -865,7 +921,7 @@ def main():
|
||||||
print(f"\n=== Первый проход ===")
|
print(f"\n=== Первый проход ===")
|
||||||
print(f" .text: {len(text_buffer)} байт, vaddr=0x{vaddr_text:x}")
|
print(f" .text: {len(text_buffer)} байт, vaddr=0x{vaddr_text: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" .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" .bnd: {bss_size} байт, vaddr=0x{vaddr_bnd_final:x} (только в памяти)")
|
||||||
print(f" точка входа: {entry_point} = 0x{labels.get(entry_point, vaddr_text):x}")
|
print(f" точка входа: {entry_point} = 0x{labels.get(entry_point, vaddr_text):x}")
|
||||||
print(f" меток: {len(labels)}")
|
print(f" меток: {len(labels)}")
|
||||||
print(f" констант: {len(symbols)}")
|
print(f" констант: {len(symbols)}")
|
||||||
|
|
|
||||||
878
инструменты/kvs_pass1 copy.py
Normal file
878
инструменты/kvs_pass1 copy.py
Normal file
|
|
@ -0,0 +1,878 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Первый проход КВС (однопроходная версия с заглушками)
|
||||||
|
Генерирует CSV-таблицу напрямую из AST
|
||||||
|
- Неизвестные метки заменяются заглушками (0xCC) с пометкой в колонке 'уводящий_адрес'
|
||||||
|
- В колонке 'приводящая_метка' записываются имена меток, находящихся по данному адресу (через запятую)
|
||||||
|
- Колонка 'команда_со_значениями' оставлена пустой (для второго прохода)
|
||||||
|
- Колонки 'рассчитанный_уводящий_адрес' и 'рассчитанный_байт' оставлены для второго прохода
|
||||||
|
- Колонка 'виртуальный_адрес' содержит виртуальный адрес байта (для pass4)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import csv
|
||||||
|
import struct # <--- НОВЫЙ ИМПОРТ
|
||||||
|
|
||||||
|
sys.path.insert(0, '.')
|
||||||
|
from kvs_data import (
|
||||||
|
PAGE_SIZE, text_vaddr_base, align_up,
|
||||||
|
ALWAYS_STUB_INSTRUCTIONS
|
||||||
|
)
|
||||||
|
from kvs_encoder import encode_instruction
|
||||||
|
|
||||||
|
# ========== ГЛОБАЛЬНОЕ СОСТОЯНИЕ ==========
|
||||||
|
entries = []
|
||||||
|
current_address = 0
|
||||||
|
current_segment = '.header'
|
||||||
|
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()
|
||||||
|
bnd_size = 0
|
||||||
|
|
||||||
|
labels = {}
|
||||||
|
label_sections = {}
|
||||||
|
symbols = {}
|
||||||
|
|
||||||
|
pending_labels = []
|
||||||
|
|
||||||
|
text_pos = 0
|
||||||
|
data_pos = 0
|
||||||
|
|
||||||
|
entry_point = "_start"
|
||||||
|
relocations = []
|
||||||
|
|
||||||
|
|
||||||
|
def reset_state():
|
||||||
|
global entries, current_address, current_segment, last_segment
|
||||||
|
global text_buffer, data_buffer, bnd_size, vaddr_data, vaddr_bnd
|
||||||
|
global labels, label_sections, symbols, text_pos, data_pos, entry_point, relocations
|
||||||
|
global pending_labels
|
||||||
|
|
||||||
|
entries = []
|
||||||
|
current_address = 0
|
||||||
|
current_segment = '.header'
|
||||||
|
last_segment = None
|
||||||
|
text_buffer = bytearray()
|
||||||
|
data_buffer = bytearray()
|
||||||
|
bnd_size = 0
|
||||||
|
vaddr_data = None
|
||||||
|
vaddr_bnd = None
|
||||||
|
data_offset = 0x2000 # добавить
|
||||||
|
labels = {}
|
||||||
|
label_sections = {}
|
||||||
|
symbols = {}
|
||||||
|
text_pos = 0
|
||||||
|
data_pos = 0
|
||||||
|
entry_point = "_start"
|
||||||
|
relocations = []
|
||||||
|
pending_labels = []
|
||||||
|
|
||||||
|
|
||||||
|
def set_segment(segment: str):
|
||||||
|
global current_segment
|
||||||
|
current_segment = segment
|
||||||
|
|
||||||
|
|
||||||
|
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 - data_offset)
|
||||||
|
else:
|
||||||
|
return current_address
|
||||||
|
|
||||||
|
|
||||||
|
def add_byte(value: int, source: str = "", target=None, labels_list=None):
|
||||||
|
global current_address, last_segment, pending_labels
|
||||||
|
|
||||||
|
effective_labels = ""
|
||||||
|
if labels_list is not None and labels_list:
|
||||||
|
effective_labels = ','.join(labels_list)
|
||||||
|
elif pending_labels:
|
||||||
|
effective_labels = ','.join(pending_labels)
|
||||||
|
|
||||||
|
show_segment = current_segment# if current_segment != last_segment else None
|
||||||
|
if show_segment:
|
||||||
|
last_segment = current_segment
|
||||||
|
|
||||||
|
virt_addr = get_virtual_address()
|
||||||
|
byte_val = value & 0xFF
|
||||||
|
|
||||||
|
entries.append((
|
||||||
|
show_segment if show_segment else "",
|
||||||
|
current_address,
|
||||||
|
f"0x{virt_addr:08x}",
|
||||||
|
f"0x{byte_val:02x}",
|
||||||
|
target if target else "",
|
||||||
|
source,
|
||||||
|
effective_labels,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
f"0x{byte_val:02x}"
|
||||||
|
))
|
||||||
|
current_address += 1
|
||||||
|
|
||||||
|
if pending_labels:
|
||||||
|
pending_labels = []
|
||||||
|
|
||||||
|
|
||||||
|
def add_bytes(values, source: str = "", target=None):
|
||||||
|
for i, v in enumerate(values):
|
||||||
|
add_byte(v, source if i == 0 else "", target if i == 0 else None)
|
||||||
|
|
||||||
|
|
||||||
|
# ========== РЕФАКТОРИНГ: ИСПОЛЬЗУЕМ struct.pack ==========
|
||||||
|
|
||||||
|
def add_word16(value: int, source: str = "", target=None):
|
||||||
|
"""Добавляет 16-битное значение (little-endian)"""
|
||||||
|
add_bytes(struct.pack('<H', value & 0xFFFF), source, target)
|
||||||
|
|
||||||
|
|
||||||
|
def add_word32(value: int, source: str = "", target=None):
|
||||||
|
"""Добавляет 32-битное значение (little-endian)"""
|
||||||
|
add_bytes(struct.pack('<I', value & 0xFFFFFFFF), source, target)
|
||||||
|
|
||||||
|
|
||||||
|
def add_word64(value: int, source: str = "", target=None):
|
||||||
|
"""Добавляет 64-битное значение (little-endian)"""
|
||||||
|
add_bytes(struct.pack('<Q', value & 0xFFFFFFFFFFFFFFFF), source, target)
|
||||||
|
|
||||||
|
|
||||||
|
def add_dwords(values: list, source: str = "", target=None):
|
||||||
|
"""Добавляет несколько 32-битных значений"""
|
||||||
|
for val in values:
|
||||||
|
add_word32(val, source, target)
|
||||||
|
|
||||||
|
|
||||||
|
def add_qwords(values: list, source: str = "", target=None):
|
||||||
|
"""Добавляет несколько 64-битных значений"""
|
||||||
|
for val in values:
|
||||||
|
add_word64(val, source, target)
|
||||||
|
|
||||||
|
|
||||||
|
def align_to(alignment: int):
|
||||||
|
global current_address, pending_labels
|
||||||
|
padding = (alignment - (current_address % alignment)) % alignment
|
||||||
|
if padding > 0:
|
||||||
|
pending_labels = []
|
||||||
|
current_address += padding
|
||||||
|
|
||||||
|
|
||||||
|
def unescape_string(s):
|
||||||
|
result = []
|
||||||
|
i = 0
|
||||||
|
while i < len(s):
|
||||||
|
if s[i] == '\\' and i + 1 < len(s):
|
||||||
|
if s[i + 1] == 'n':
|
||||||
|
result.append('\n')
|
||||||
|
elif s[i + 1] == 't':
|
||||||
|
result.append('\t')
|
||||||
|
elif s[i + 1] == 'r':
|
||||||
|
result.append('\r')
|
||||||
|
else:
|
||||||
|
result.append(s[i + 1])
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
result.append(s[i])
|
||||||
|
i += 1
|
||||||
|
return ''.join(result)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_elf_header():
|
||||||
|
"""Генерирует заголовок ELF (64 байта)"""
|
||||||
|
# ELF magic
|
||||||
|
add_bytes([0x7F, 0x45, 0x4C, 0x46], "ELF magic")
|
||||||
|
add_byte(2, "ELFCLASS64")
|
||||||
|
add_byte(1, "ELFDATA2LSB")
|
||||||
|
add_byte(1, "ELF version")
|
||||||
|
add_byte(0, "OS ABI")
|
||||||
|
add_byte(0, "ABI version")
|
||||||
|
add_bytes([0] * 7, "Padding")
|
||||||
|
|
||||||
|
# e_type, e_machine, e_version
|
||||||
|
add_word16(2, "e_type = ET_EXEC")
|
||||||
|
add_word16(62, "e_machine = EM_X86_64")
|
||||||
|
add_word32(1, "e_version")
|
||||||
|
|
||||||
|
# e_entry (stub - будет заполнен позже)
|
||||||
|
add_word64(0, "e_entry (stub)")
|
||||||
|
|
||||||
|
# e_phoff, e_shoff
|
||||||
|
add_word64(64, "e_phoff")
|
||||||
|
add_word64(0, "e_shoff = 0")
|
||||||
|
|
||||||
|
# e_flags, e_ehsize, e_phentsize
|
||||||
|
add_word32(0, "e_flags")
|
||||||
|
add_word16(64, "e_ehsize")
|
||||||
|
add_word16(56, "e_phentsize")
|
||||||
|
|
||||||
|
# e_phnum, e_shentsize, e_shnum, e_shstrndx
|
||||||
|
add_word16(2, "e_phnum = 2")
|
||||||
|
add_word16(0, "e_shentsize = 0")
|
||||||
|
add_word16(0, "e_shnum = 0")
|
||||||
|
add_word16(0, "e_shstrndx")
|
||||||
|
|
||||||
|
|
||||||
|
def generate_program_headers():
|
||||||
|
"""Генерирует два программных заголовка (PT_LOAD)"""
|
||||||
|
# === Первый заголовок: TEXT (RX) ===
|
||||||
|
add_word32(1, "p_type = PT_LOAD")
|
||||||
|
add_word32(5, "p_flags = RX")
|
||||||
|
add_word64(0, "p_offset (text stub)") # будет заполнено позже
|
||||||
|
add_word64(vaddr_text, "p_vaddr (text)")
|
||||||
|
add_word64(vaddr_text, "p_paddr (text)")
|
||||||
|
add_word64(0, "p_filesz (text stub)") # будет заполнено позже
|
||||||
|
add_word64(0, "p_memsz (text stub)") # будет заполнено позже
|
||||||
|
add_word64(PAGE_SIZE, "p_align")
|
||||||
|
|
||||||
|
# === Второй заголовок: DATA (RW) ===
|
||||||
|
add_word32(1, "p_type = PT_LOAD")
|
||||||
|
add_word32(6, "p_flags = RW")
|
||||||
|
add_word64(0, "p_offset (data stub)") # будет заполнено позже
|
||||||
|
add_word64(0, "p_vaddr (data stub)") # будет заполнено позже
|
||||||
|
add_word64(0, "p_paddr (data stub)") # будет заполнено позже
|
||||||
|
add_word64(0, "p_filesz (data stub)") # будет заполнено позже
|
||||||
|
add_word64(0, "p_memsz (data stub)") # будет заполнено позже
|
||||||
|
add_word64(PAGE_SIZE, "p_align")
|
||||||
|
|
||||||
|
|
||||||
|
def read_ast(input_file):
|
||||||
|
with open(input_file, 'r', encoding='utf-8') as f:
|
||||||
|
return [line.strip() for line in f]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_ast_line(line):
|
||||||
|
if not line:
|
||||||
|
return None, {}
|
||||||
|
|
||||||
|
line_type = line.split(':')[0]
|
||||||
|
|
||||||
|
if line_type == "INSTR":
|
||||||
|
first = line.find(':')
|
||||||
|
second = line.find(':', first + 1)
|
||||||
|
third = line.find(':', second + 1)
|
||||||
|
|
||||||
|
if first == -1 or second == -1 or third == -1:
|
||||||
|
return "INSTR", {}
|
||||||
|
|
||||||
|
mnemonic = line[first + 1:second]
|
||||||
|
section = line[second + 1:third]
|
||||||
|
operands_str = line[third + 1:]
|
||||||
|
operands = operands_str.split(',') if operands_str else []
|
||||||
|
|
||||||
|
return "INSTR", {
|
||||||
|
'mnemonic': mnemonic,
|
||||||
|
'section': section,
|
||||||
|
'operands': operands
|
||||||
|
}
|
||||||
|
|
||||||
|
elif line_type == "DIRECTIVE":
|
||||||
|
parts = line.split(':')
|
||||||
|
directive = parts[1] if len(parts) > 1 else ""
|
||||||
|
|
||||||
|
if directive in ('.текст', '.данные', '.бнд'):
|
||||||
|
return "DIRECTIVE", {'directive': directive}
|
||||||
|
elif directive == '.глобал':
|
||||||
|
return "DIRECTIVE", {'directive': directive, 'label': parts[2] if len(parts) > 2 else ""}
|
||||||
|
elif directive in ('.строка', '.строка_нуль'):
|
||||||
|
return "DIRECTIVE", {
|
||||||
|
'directive': directive,
|
||||||
|
'section': parts[2] if len(parts) > 2 else "",
|
||||||
|
'string': parts[3] if len(parts) > 3 else ""
|
||||||
|
}
|
||||||
|
elif directive == '.константа':
|
||||||
|
return "DIRECTIVE", {
|
||||||
|
'directive': directive,
|
||||||
|
'name': parts[2] if len(parts) > 2 else "",
|
||||||
|
'value': parts[3] if len(parts) > 3 else ""
|
||||||
|
}
|
||||||
|
elif directive == '.байт':
|
||||||
|
return "DIRECTIVE", {
|
||||||
|
'directive': directive,
|
||||||
|
'section': parts[2] if len(parts) > 2 else "",
|
||||||
|
'bytes': parts[3] if len(parts) > 3 else ""
|
||||||
|
}
|
||||||
|
elif directive in ('.резб', '.резс', '.рездс', '.резкс'):
|
||||||
|
return "DIRECTIVE", {
|
||||||
|
'directive': directive,
|
||||||
|
'section': parts[2] if len(parts) > 2 else "",
|
||||||
|
'count': parts[3] if len(parts) > 3 else "0"
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return "DIRECTIVE", {'directive': directive}
|
||||||
|
|
||||||
|
elif line_type == "LABEL":
|
||||||
|
parts = line.split(':')
|
||||||
|
return "LABEL", {
|
||||||
|
'name': parts[1] if len(parts) > 1 else "",
|
||||||
|
'section': parts[2] if len(parts) > 2 else ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return line_type, {}
|
||||||
|
|
||||||
|
|
||||||
|
def get_stub_size(mnemonic, operands):
|
||||||
|
if mnemonic in ("переход", "вызвать"):
|
||||||
|
return 5
|
||||||
|
elif mnemonic == "короткий_переход":
|
||||||
|
return 2
|
||||||
|
elif mnemonic.startswith("переход_если") and not mnemonic.startswith("короткий"):
|
||||||
|
return 6
|
||||||
|
elif mnemonic.startswith("короткий_переход_если"):
|
||||||
|
return 2
|
||||||
|
elif mnemonic == "цикл":
|
||||||
|
return 2
|
||||||
|
elif mnemonic == "переместить_имм" and len(operands) >= 2:
|
||||||
|
reg = operands[0]
|
||||||
|
if reg in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||||
|
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'):
|
||||||
|
return 10
|
||||||
|
elif reg in ('еаикс', 'ебикс', 'есикс', 'едикс'):
|
||||||
|
return 7
|
||||||
|
else:
|
||||||
|
return 2
|
||||||
|
elif mnemonic in ("загрузить", "сохранить", "загрузить_адрес"):
|
||||||
|
return 7
|
||||||
|
elif mnemonic == "сравнить_с":
|
||||||
|
return 7
|
||||||
|
elif mnemonic in ("прибавить_непосредственно", "вычесть_непосредственно"):
|
||||||
|
return 7
|
||||||
|
elif mnemonic in ("переместить_с_нулями", "переместить_со_знаком"):
|
||||||
|
return 7
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def extract_label_from_operands(operands):
|
||||||
|
"""Извлекает первую метку из операндов инструкции"""
|
||||||
|
for op in operands:
|
||||||
|
if not op:
|
||||||
|
continue
|
||||||
|
# Пропускаем регистры
|
||||||
|
if op in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||||
|
'еаикс', 'ебикс', 'есикс', 'едикс',
|
||||||
|
'аикс', 'бикс', 'сикс', 'дикс',
|
||||||
|
'ал', 'бл', 'кл', 'дл',
|
||||||
|
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'):
|
||||||
|
continue
|
||||||
|
# Пропускаем числа
|
||||||
|
if op.isdigit() or (op.startswith('0x') and len(op) > 2):
|
||||||
|
continue
|
||||||
|
# Пропускаем косвенную адресацию через регистр
|
||||||
|
if op.startswith('MEM:reg_indirect:'):
|
||||||
|
continue
|
||||||
|
# Извлекаем метку из [метка]
|
||||||
|
if op.startswith('[') and op.endswith(']'):
|
||||||
|
inner = op[1:-1]
|
||||||
|
if inner not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай'):
|
||||||
|
if not inner.isdigit() and not inner.startswith('0x'):
|
||||||
|
return inner
|
||||||
|
# Обычная метка
|
||||||
|
elif op not in symbols:
|
||||||
|
return op
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def has_unresolved_labels(operands, mnemonic=""):
|
||||||
|
if mnemonic in ALWAYS_STUB_INSTRUCTIONS:
|
||||||
|
for op in operands:
|
||||||
|
if op and not op.isdigit() and not op.startswith('0x'):
|
||||||
|
if op not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||||
|
'еаикс', 'ебикс', 'есикс', 'едикс',
|
||||||
|
'аикс', 'бикс', 'сикс', 'дикс',
|
||||||
|
'ал', 'бл', 'кл', 'дл'):
|
||||||
|
return True
|
||||||
|
|
||||||
|
for op in operands:
|
||||||
|
if not op:
|
||||||
|
continue
|
||||||
|
if op in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||||
|
'еаикс', 'ебикс', 'есикс', 'едикс',
|
||||||
|
'аикс', 'бикс', 'сикс', 'дикс',
|
||||||
|
'ал', 'бл', 'кл', 'дл',
|
||||||
|
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15',
|
||||||
|
'р8д', 'р9д', 'р10д', 'р11д', 'р12д', 'р13д', 'р14д', 'р15д',
|
||||||
|
'р8в', 'р9в', 'р10в', 'р11в', 'р12в', 'р13в', 'р14в', 'р15в',
|
||||||
|
'р8б', 'р9б', 'р10б', 'р11б', 'р12б', 'р13б', 'р14б', 'р15б',
|
||||||
|
'спл', 'бпл', 'сил', 'дил'):
|
||||||
|
continue
|
||||||
|
if op.startswith('MEM:reg_indirect:'):
|
||||||
|
continue
|
||||||
|
if op.startswith('[') and op.endswith(']'):
|
||||||
|
inner = op[1:-1]
|
||||||
|
if inner in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай'):
|
||||||
|
continue
|
||||||
|
if inner.isdigit() or (inner.startswith('0x') and len(inner) > 2):
|
||||||
|
continue
|
||||||
|
if inner not in labels:
|
||||||
|
return True
|
||||||
|
continue
|
||||||
|
if op.isdigit() or (op.startswith('0x') and len(op) > 2):
|
||||||
|
continue
|
||||||
|
if op in symbols:
|
||||||
|
continue
|
||||||
|
if op not in labels:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_unresolved_labels(operands):
|
||||||
|
unresolved = []
|
||||||
|
for op in operands:
|
||||||
|
if not op:
|
||||||
|
continue
|
||||||
|
if op.startswith('[') and op.endswith(']'):
|
||||||
|
inner = op[1:-1]
|
||||||
|
if inner not in labels and not inner.isdigit() and not (inner.startswith('0x')):
|
||||||
|
if inner not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай'):
|
||||||
|
if inner not in symbols:
|
||||||
|
unresolved.append(inner)
|
||||||
|
elif op not in labels and not op.isdigit() and not (op.startswith('0x')):
|
||||||
|
if op not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||||
|
'еаикс', 'ебикс', 'есикс', 'едикс',
|
||||||
|
'аикс', 'бикс', 'сикс', 'дикс',
|
||||||
|
'ал', 'бл', 'кл', 'дл',
|
||||||
|
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'):
|
||||||
|
if op not in symbols:
|
||||||
|
unresolved.append(op)
|
||||||
|
return unresolved
|
||||||
|
|
||||||
|
|
||||||
|
def process_ast_line(line):
|
||||||
|
global text_pos, data_pos, vaddr_data, vaddr_bnd, bnd_size
|
||||||
|
global text_buffer, data_buffer, entry_point, symbols, pending_labels
|
||||||
|
|
||||||
|
line_type, fields = parse_ast_line(line)
|
||||||
|
|
||||||
|
if line_type == "DIRECTIVE":
|
||||||
|
directive = fields.get('directive', '')
|
||||||
|
|
||||||
|
if directive == '.текст':
|
||||||
|
set_segment('.text')
|
||||||
|
|
||||||
|
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')
|
||||||
|
|
||||||
|
elif directive == '.глобал':
|
||||||
|
entry_point = fields.get('label', '_start')
|
||||||
|
|
||||||
|
elif directive == '.константа':
|
||||||
|
name = fields.get('name', '')
|
||||||
|
value_str = fields.get('value', '')
|
||||||
|
if value_str.startswith('0x') or value_str.startswith('0X'):
|
||||||
|
value = int(value_str, 16)
|
||||||
|
else:
|
||||||
|
value = int(value_str)
|
||||||
|
symbols[name] = value
|
||||||
|
print(f" константа: {name} = {value}")
|
||||||
|
|
||||||
|
elif directive in ('.строка', '.строка_нуль'):
|
||||||
|
s = fields.get('string', '')
|
||||||
|
real_s = unescape_string(s)
|
||||||
|
bstring = real_s.encode('utf-8')
|
||||||
|
if directive == '.строка_нуль':
|
||||||
|
bstring += b'\x00'
|
||||||
|
|
||||||
|
source = f'{directive} "{s}"'
|
||||||
|
|
||||||
|
for i, byte in enumerate(bstring):
|
||||||
|
labels_list = pending_labels if i == 0 else None
|
||||||
|
add_byte(byte, source if i == 0 else "", None, labels_list)
|
||||||
|
data_buffer.append(byte)
|
||||||
|
if labels_list:
|
||||||
|
pending_labels = []
|
||||||
|
data_pos += len(bstring)
|
||||||
|
|
||||||
|
elif directive == '.байт':
|
||||||
|
bytes_str = fields.get('bytes', '')
|
||||||
|
if bytes_str:
|
||||||
|
byte_values = bytes_str.split(',')
|
||||||
|
source = f'.байт {bytes_str}'
|
||||||
|
bstring = bytearray()
|
||||||
|
for byte_str in byte_values:
|
||||||
|
byte_str = byte_str.strip()
|
||||||
|
if byte_str.startswith('0x'):
|
||||||
|
val = int(byte_str, 16)
|
||||||
|
else:
|
||||||
|
val = int(byte_str)
|
||||||
|
bstring.append(val & 0xFF)
|
||||||
|
|
||||||
|
for i, byte in enumerate(bstring):
|
||||||
|
labels_list = pending_labels if i == 0 else None
|
||||||
|
add_byte(byte, source if i == 0 else "", None, labels_list)
|
||||||
|
data_buffer.append(byte)
|
||||||
|
if labels_list:
|
||||||
|
pending_labels = []
|
||||||
|
data_pos += len(bstring)
|
||||||
|
|
||||||
|
elif directive in ('.резб', '.резс', '.рездс', '.резкс'):
|
||||||
|
count = int(fields.get('count', '0'))
|
||||||
|
multiplier = {'резб': 1, 'резс': 2, 'рездс': 4, 'резкс': 8}
|
||||||
|
bnd_size += count * multiplier.get(directive, 1)
|
||||||
|
|
||||||
|
elif line_type == "LABEL":
|
||||||
|
label_name = fields.get('name', '')
|
||||||
|
sec = fields.get('section', '')
|
||||||
|
|
||||||
|
if sec == '.text':
|
||||||
|
addr = vaddr_text + text_pos
|
||||||
|
labels[label_name] = addr
|
||||||
|
label_sections[label_name] = sec
|
||||||
|
if label_name not in pending_labels:
|
||||||
|
pending_labels.append(label_name)
|
||||||
|
|
||||||
|
elif sec == '.data':
|
||||||
|
if vaddr_data is None:
|
||||||
|
vaddr_data = align_up(vaddr_text + text_pos, PAGE_SIZE)
|
||||||
|
addr = vaddr_data + data_pos
|
||||||
|
labels[label_name] = addr
|
||||||
|
label_sections[label_name] = sec
|
||||||
|
if label_name not in pending_labels:
|
||||||
|
pending_labels.append(label_name)
|
||||||
|
|
||||||
|
elif sec == '.бнд':
|
||||||
|
if vaddr_bnd is None:
|
||||||
|
vaddr_bnd = align_up(vaddr_data + data_pos, PAGE_SIZE)
|
||||||
|
addr = vaddr_bnd + bnd_size
|
||||||
|
labels[label_name] = addr
|
||||||
|
label_sections[label_name] = sec
|
||||||
|
if label_name not in pending_labels:
|
||||||
|
pending_labels.append(label_name)
|
||||||
|
|
||||||
|
else:
|
||||||
|
addr = current_address
|
||||||
|
labels[label_name] = addr
|
||||||
|
label_sections[label_name] = sec
|
||||||
|
if label_name not in pending_labels:
|
||||||
|
pending_labels.append(label_name)
|
||||||
|
|
||||||
|
elif line_type == "INSTR":
|
||||||
|
mnemonic = fields.get('mnemonic', '')
|
||||||
|
sec = fields.get('section', '')
|
||||||
|
operands = fields.get('operands', [])
|
||||||
|
|
||||||
|
source = f"{mnemonic} {', '.join(operands)}" if operands else mnemonic
|
||||||
|
|
||||||
|
need_stub = has_unresolved_labels(operands, mnemonic)
|
||||||
|
|
||||||
|
if need_stub:
|
||||||
|
stub_size = get_stub_size(mnemonic, operands)
|
||||||
|
unresolved = get_unresolved_labels(operands)
|
||||||
|
|
||||||
|
if unresolved:
|
||||||
|
reloc_text = f"ЗАГЛУШКА {', '.join(unresolved)}"
|
||||||
|
else:
|
||||||
|
label_from_op = extract_label_from_operands(operands)
|
||||||
|
if label_from_op:
|
||||||
|
reloc_text = f"ЗАГЛУШКА {label_from_op}"
|
||||||
|
else:
|
||||||
|
reloc_text = "ЗАГЛУШКА (неизвестная метка)"
|
||||||
|
|
||||||
|
relocations.append({
|
||||||
|
'address': current_address,
|
||||||
|
'size': stub_size,
|
||||||
|
'labels': unresolved if unresolved else [label_from_op] if label_from_op else [],
|
||||||
|
'source': source,
|
||||||
|
'mnemonic': mnemonic
|
||||||
|
})
|
||||||
|
|
||||||
|
for i in range(stub_size):
|
||||||
|
labels_list = pending_labels if i == 0 else None
|
||||||
|
add_byte(0xCC, source if i == 0 else "", reloc_text if i == 0 else None, labels_list)
|
||||||
|
if labels_list:
|
||||||
|
pending_labels = []
|
||||||
|
|
||||||
|
if sec == '.text':
|
||||||
|
text_buffer.extend([0xCC] * stub_size)
|
||||||
|
text_pos += stub_size
|
||||||
|
else:
|
||||||
|
data_buffer.extend([0xCC] * stub_size)
|
||||||
|
data_pos += stub_size
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if sec == '.text':
|
||||||
|
current_pos = text_pos
|
||||||
|
else:
|
||||||
|
current_pos = data_pos
|
||||||
|
|
||||||
|
encoded = encode_instruction(
|
||||||
|
mnemonic, operands, labels, label_sections, symbols,
|
||||||
|
vaddr_text, vaddr_data if vaddr_data else 0,
|
||||||
|
current_pos, vaddr_bnd if vaddr_bnd else 0
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, byte in enumerate(encoded):
|
||||||
|
labels_list = pending_labels if i == 0 else None
|
||||||
|
add_byte(byte, source if i == 0 else "", None, labels_list)
|
||||||
|
if labels_list:
|
||||||
|
pending_labels = []
|
||||||
|
|
||||||
|
if sec == '.text':
|
||||||
|
text_buffer.extend(encoded)
|
||||||
|
text_pos += len(encoded)
|
||||||
|
else:
|
||||||
|
data_buffer.extend(encoded)
|
||||||
|
data_pos += len(encoded)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка кодирования {source}: {e}", file=sys.stderr)
|
||||||
|
labels_to_attach = pending_labels.copy()
|
||||||
|
add_byte(0xCC, source, f"ОШИБКА: {e}", labels_to_attach)
|
||||||
|
pending_labels.clear()
|
||||||
|
|
||||||
|
if sec == '.text':
|
||||||
|
text_buffer.append(0xCC)
|
||||||
|
text_pos += 1
|
||||||
|
else:
|
||||||
|
data_buffer.append(0xCC)
|
||||||
|
data_pos += 1
|
||||||
|
|
||||||
|
|
||||||
|
def finalize_headers():
|
||||||
|
global entries, data_offset # добавить data_offset в global
|
||||||
|
|
||||||
|
text_offset = 0x1000
|
||||||
|
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
|
||||||
|
|
||||||
|
vaddr_data_final = align_up(vaddr_text + text_filesz, PAGE_SIZE)
|
||||||
|
entry_point_addr = labels.get(entry_point, vaddr_text)
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i < len(entries):
|
||||||
|
segment, addr, virt_addr, byte_str, target, source, label, cmd_with_values, calc_target, calc_byte = entries[i]
|
||||||
|
|
||||||
|
if 'e_entry (stub)' in source:
|
||||||
|
# Вставляем 8 байт (uint64_t)
|
||||||
|
new_bytes = struct.pack('<Q', entry_point_addr)
|
||||||
|
for j, nb in enumerate(new_bytes):
|
||||||
|
virt = f"0x{entry_point_addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
|
f"e_entry = 0x{entry_point_addr:x}",
|
||||||
|
label if j == 0 else "",
|
||||||
|
"", "", byte_hex)
|
||||||
|
i += 8
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif 'p_offset (text stub)' in source:
|
||||||
|
new_bytes = struct.pack('<Q', text_offset)
|
||||||
|
for j, nb in enumerate(new_bytes):
|
||||||
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
|
f"p_offset (text) = 0x{text_offset:x}",
|
||||||
|
label if j == 0 else "",
|
||||||
|
"", "", byte_hex)
|
||||||
|
i += 8
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif 'p_filesz (text stub)' in source:
|
||||||
|
new_bytes = struct.pack('<Q', text_filesz)
|
||||||
|
for j, nb in enumerate(new_bytes):
|
||||||
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
|
f"p_filesz (text) = {text_filesz}",
|
||||||
|
label if j == 0 else "",
|
||||||
|
"", "", byte_hex)
|
||||||
|
i += 8
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif 'p_memsz (text stub)' in source:
|
||||||
|
new_bytes = struct.pack('<Q', text_memsz)
|
||||||
|
for j, nb in enumerate(new_bytes):
|
||||||
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
|
f"p_memsz (text) = {text_memsz}",
|
||||||
|
label if j == 0 else "",
|
||||||
|
"", "", byte_hex)
|
||||||
|
i += 8
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif 'p_offset (data stub)' in source:
|
||||||
|
new_bytes = struct.pack('<Q', data_offset)
|
||||||
|
for j, nb in enumerate(new_bytes):
|
||||||
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
|
f"p_offset (data) = 0x{data_offset:x}",
|
||||||
|
label if j == 0 else "",
|
||||||
|
"", "", byte_hex)
|
||||||
|
i += 8
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif 'p_vaddr (data stub)' in source:
|
||||||
|
new_bytes = struct.pack('<Q', vaddr_data_final)
|
||||||
|
for j, nb in enumerate(new_bytes):
|
||||||
|
virt = f"0x{vaddr_data_final + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
|
f"p_vaddr (data) = 0x{vaddr_data_final:x}",
|
||||||
|
label if j == 0 else "",
|
||||||
|
"", "", byte_hex)
|
||||||
|
i += 8
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif 'p_paddr (data stub)' in source:
|
||||||
|
new_bytes = struct.pack('<Q', vaddr_data_final)
|
||||||
|
for j, nb in enumerate(new_bytes):
|
||||||
|
virt = f"0x{vaddr_data_final + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
|
f"p_paddr (data) = 0x{vaddr_data_final:x}",
|
||||||
|
label if j == 0 else "",
|
||||||
|
"", "", byte_hex)
|
||||||
|
i += 8
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif 'p_filesz (data stub)' in source:
|
||||||
|
new_bytes = struct.pack('<Q', data_filesz)
|
||||||
|
for j, nb in enumerate(new_bytes):
|
||||||
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
|
f"p_filesz (data) = {data_filesz}",
|
||||||
|
label if j == 0 else "",
|
||||||
|
"", "", byte_hex)
|
||||||
|
i += 8
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif 'p_memsz (data stub)' in source:
|
||||||
|
new_bytes = struct.pack('<Q', data_memsz)
|
||||||
|
for j, nb in enumerate(new_bytes):
|
||||||
|
virt = f"0x{addr + j:08x}"
|
||||||
|
byte_hex = f"0x{nb:02x}"
|
||||||
|
entries[i + j] = (segment, addr + j, virt, byte_hex, target,
|
||||||
|
f"p_memsz (data) = {data_memsz}",
|
||||||
|
label if j == 0 else "",
|
||||||
|
"", "", byte_hex)
|
||||||
|
i += 8
|
||||||
|
continue
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
|
||||||
|
def save_to_csv(filename: str):
|
||||||
|
with open(filename, 'w', newline='', encoding='utf-8') as f:
|
||||||
|
writer = csv.writer(f, delimiter=';')
|
||||||
|
writer.writerow(['сегмент', 'адрес', 'виртуальный_адрес', 'байт', 'приводящая_метка',
|
||||||
|
'уводящий_адрес', 'исходная_команда', 'команда_со_значениями',
|
||||||
|
'рассчитанный_уводящий_адрес', 'рассчитанный_байт'])
|
||||||
|
|
||||||
|
for segment, addr, virt_addr, byte_str, target, source, label, cmd_with_values, calc_target, calc_byte in entries:
|
||||||
|
writer.writerow([
|
||||||
|
segment,
|
||||||
|
f"0x{addr:08x}",
|
||||||
|
virt_addr,
|
||||||
|
byte_str,
|
||||||
|
label,
|
||||||
|
target,
|
||||||
|
source,
|
||||||
|
cmd_with_values,
|
||||||
|
calc_target,
|
||||||
|
calc_byte
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
ast_file = sys.argv[1]
|
||||||
|
csv_file = sys.argv[2]
|
||||||
|
|
||||||
|
reset_state()
|
||||||
|
|
||||||
|
set_segment('.header')
|
||||||
|
generate_elf_header()
|
||||||
|
generate_program_headers()
|
||||||
|
align_to(PAGE_SIZE)
|
||||||
|
|
||||||
|
ast_lines = read_ast(ast_file)
|
||||||
|
for line in ast_lines:
|
||||||
|
process_ast_line(line)
|
||||||
|
|
||||||
|
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}, 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)}")
|
||||||
|
print(f" констант: {len(symbols)}")
|
||||||
|
print(f" релокаций: {len(relocations)}")
|
||||||
|
print(f" записей: {len(entries)}")
|
||||||
|
print(f" CSV: {csv_file}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
45
тесты/тест_бнд2.квс
Normal file
45
тесты/тест_бнд2.квс
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
.текст
|
||||||
|
.глобал _start
|
||||||
|
|
||||||
|
_start:
|
||||||
|
; =============================================
|
||||||
|
; ТЕСТ 1: Абсолютная адресация в .бнд
|
||||||
|
; =============================================
|
||||||
|
переместить_имм раикс, 0x42
|
||||||
|
сохранить [абс_перем], раикс
|
||||||
|
|
||||||
|
; =============================================
|
||||||
|
; ТЕСТ 2: Косвенная адресация в .бнд
|
||||||
|
; =============================================
|
||||||
|
переместить_имм рбикс, косв_перем
|
||||||
|
переместить_имм раикс, 0x99
|
||||||
|
сохранить [рбикс], раикс
|
||||||
|
|
||||||
|
; =============================================
|
||||||
|
; ТЕСТ 3: Ещё одна косвенная адресация в .бнд
|
||||||
|
; =============================================
|
||||||
|
переместить_имм рсикс, ещё_перем
|
||||||
|
переместить_имм раикс, 0x77
|
||||||
|
сохранить [рсикс], раикс
|
||||||
|
|
||||||
|
; =============================================
|
||||||
|
; Читаем всё обратно
|
||||||
|
; =============================================
|
||||||
|
загрузить р8, [абс_перем]
|
||||||
|
загрузить р9, [рбикс]
|
||||||
|
загрузить р10, [рсикс]
|
||||||
|
|
||||||
|
; =============================================
|
||||||
|
; ЗАВЕРШЕНИЕ: возвращаем из абс_перем
|
||||||
|
; =============================================
|
||||||
|
загрузить рдиай, [абс_перем]
|
||||||
|
переместить_имм раикс, 60
|
||||||
|
вызов_системы
|
||||||
|
|
||||||
|
.данные
|
||||||
|
пустые_данные: .байт 0
|
||||||
|
|
||||||
|
.бнд
|
||||||
|
абс_перем: .резб 1
|
||||||
|
косв_перем: .резб 1
|
||||||
|
ещё_перем: .резб 8
|
||||||
Loading…
Reference in a new issue