адресация в bss

This commit is contained in:
mzhoot 2026-05-25 20:36:43 +03:00
parent a75dc24a61
commit 403b999d42
3 changed files with 1049 additions and 70 deletions

View file

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

View 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',
'р', 'р', 'р10д', 'р11д', 'р12д', 'р13д', 'р14д', 'р15д',
'р', 'р', 'р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()

View file

@ -0,0 +1,45 @@
.текст
.глобал _start
_start:
; =============================================
; ТЕСТ 1: Абсолютная адресация в .бнд
; =============================================
переместить_имм раикс, 0x42
сохранить [абс_перем], раикс
; =============================================
; ТЕСТ 2: Косвенная адресация в .бнд
; =============================================
переместить_имм рбикс, косв_перем
переместить_имм раикс, 0x99
сохранить [рбикс], раикс
; =============================================
; ТЕСТ 3: Ещё одна косвенная адресация в .бнд
; =============================================
переместить_имм рсикс, ещё_перем
переместить_имм раикс, 0x77
сохранить [рсикс], раикс
; =============================================
; Читаем всё обратно
; =============================================
загрузить р8, [абс_перем]
загрузить р9, [рбикс]
загрузить р10, [рсикс]
; =============================================
; ЗАВЕРШЕНИЕ: возвращаем из абс_перем
; =============================================
загрузить рдиай, [абс_перем]
переместить_имм раикс, 60
вызов_системы
.данные
пустыеанные: .байт 0
.бнд
абс_перем: .резб 1
косв_перем: .резб 1
ещё_перем: .резб 8