2026-05-23 08:52:52 +03:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
Четвёртый проход КВС
|
|
|
|
|
|
- Перекодирует инструкции, используя подставленные значения
|
2026-05-23 18:56:43 +03:00
|
|
|
|
- Смотрит колонку 'команда_со_значениями'
|
2026-05-23 08:52:52 +03:00
|
|
|
|
- Записывает перекодированные байты в колонку 'рассчитанный_байт'
|
2026-05-23 18:56:43 +03:00
|
|
|
|
- Использует виртуальные адреса из CSV для вычисления смещений
|
2026-05-23 08:52:52 +03:00
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
|
import csv
|
|
|
|
|
|
|
|
|
|
|
|
sys.path.insert(0, '.')
|
|
|
|
|
|
from kvs_data import PAGE_SIZE, text_vaddr_base, align_up
|
|
|
|
|
|
from kvs_encoder import encode_instruction
|
|
|
|
|
|
|
|
|
|
|
|
# ========== ГЛОБАЛЬНОЕ СОСТОЯНИЕ ==========
|
2026-05-23 21:14:49 +03:00
|
|
|
|
vaddr_text = None # будет прочитано из CSV
|
|
|
|
|
|
vaddr_data = None # будет прочитано из CSV
|
|
|
|
|
|
vaddr_bnd = None # будет прочитано из CSV
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
labels = {}
|
|
|
|
|
|
label_sections = {}
|
|
|
|
|
|
symbols = {}
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def read_csv(csv_file):
|
|
|
|
|
|
entries = []
|
|
|
|
|
|
headers = []
|
|
|
|
|
|
|
|
|
|
|
|
with open(csv_file, 'r', encoding='utf-8') as f:
|
|
|
|
|
|
reader = csv.reader(f, delimiter=';')
|
|
|
|
|
|
headers = next(reader)
|
|
|
|
|
|
for row in reader:
|
|
|
|
|
|
entries.append(row)
|
|
|
|
|
|
|
|
|
|
|
|
return headers, entries
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def parse_command(cmd_str):
|
|
|
|
|
|
if not cmd_str:
|
|
|
|
|
|
return None, []
|
|
|
|
|
|
|
|
|
|
|
|
parts = cmd_str.split(' ', 1)
|
|
|
|
|
|
mnemonic = parts[0]
|
|
|
|
|
|
|
|
|
|
|
|
operands = []
|
|
|
|
|
|
if len(parts) > 1 and parts[1]:
|
|
|
|
|
|
operands = [op.strip() for op in parts[1].split(',')]
|
|
|
|
|
|
|
|
|
|
|
|
return mnemonic, operands
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-25 18:19:13 +03:00
|
|
|
|
def detect_section_addresses(entries, headers, log_file):
|
2026-05-23 21:14:49 +03:00
|
|
|
|
"""
|
|
|
|
|
|
Определяет виртуальные адреса секций из CSV.
|
|
|
|
|
|
"""
|
|
|
|
|
|
global vaddr_text, vaddr_data, vaddr_bnd
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
segment_idx = headers.index('сегмент')
|
|
|
|
|
|
virt_addr_idx = headers.index('виртуальный_адрес')
|
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
|
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
found_text = False
|
|
|
|
|
|
found_data = False
|
|
|
|
|
|
found_bnd = False
|
|
|
|
|
|
|
|
|
|
|
|
for row in entries:
|
|
|
|
|
|
segment = row[segment_idx].strip()
|
|
|
|
|
|
virt_addr_str = row[virt_addr_idx].strip()
|
|
|
|
|
|
|
|
|
|
|
|
if not virt_addr_str.startswith('0x'):
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
virt_addr = int(virt_addr_str, 16)
|
|
|
|
|
|
|
|
|
|
|
|
if segment == '.text' and not found_text:
|
|
|
|
|
|
vaddr_text = virt_addr
|
|
|
|
|
|
found_text = True
|
2026-05-25 18:19:13 +03:00
|
|
|
|
log_file.write(f" .text: 0x{vaddr_text:x}\n")
|
2026-05-23 21:14:49 +03:00
|
|
|
|
|
|
|
|
|
|
elif segment == '.data' and not found_data:
|
|
|
|
|
|
vaddr_data = virt_addr
|
|
|
|
|
|
found_data = True
|
2026-05-25 18:19:13 +03:00
|
|
|
|
log_file.write(f" .data: 0x{vaddr_data:x}\n")
|
2026-05-23 21:14:49 +03:00
|
|
|
|
|
|
|
|
|
|
elif segment == '.bss' and not found_bnd:
|
|
|
|
|
|
vaddr_bnd = virt_addr
|
|
|
|
|
|
found_bnd = True
|
2026-05-25 18:19:13 +03:00
|
|
|
|
log_file.write(f" .bss: 0x{vaddr_bnd:x}\n")
|
2026-05-23 21:14:49 +03:00
|
|
|
|
|
|
|
|
|
|
# Проверяем, что все нужные секции найдены
|
|
|
|
|
|
if not found_text:
|
|
|
|
|
|
print(" Ошибка: секция .text не найдена в CSV")
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
if not found_data:
|
2026-05-25 18:19:13 +03:00
|
|
|
|
log_file.write(" Предупреждение: секция .data не найдена в CSV, используем 0x402000\n")
|
2026-05-23 21:14:49 +03:00
|
|
|
|
vaddr_data = 0x402000 # fallback
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-25 18:19:13 +03:00
|
|
|
|
def collect_labels_from_csv(entries, headers, log_file):
|
2026-05-23 18:56:43 +03:00
|
|
|
|
"""
|
|
|
|
|
|
Собирает метки из CSV, используя колонку 'виртуальный_адрес'
|
|
|
|
|
|
"""
|
|
|
|
|
|
global labels, label_sections
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
label_idx = headers.index('приводящая_метка')
|
2026-05-23 18:56:43 +03:00
|
|
|
|
virt_addr_idx = headers.index('виртуальный_адрес')
|
2026-05-23 08:52:52 +03:00
|
|
|
|
except ValueError as e:
|
|
|
|
|
|
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
for row in entries:
|
|
|
|
|
|
label_str = row[label_idx].strip()
|
|
|
|
|
|
if label_str:
|
2026-05-23 18:56:43 +03:00
|
|
|
|
virt_addr_str = row[virt_addr_idx].strip()
|
|
|
|
|
|
if virt_addr_str.startswith('0x'):
|
|
|
|
|
|
virt_addr = int(virt_addr_str, 16)
|
|
|
|
|
|
|
2026-05-23 08:52:52 +03:00
|
|
|
|
for label_name in label_str.split(','):
|
|
|
|
|
|
label_name = label_name.strip()
|
|
|
|
|
|
if label_name:
|
2026-05-23 18:56:43 +03:00
|
|
|
|
labels[label_name] = virt_addr
|
|
|
|
|
|
label_sections[label_name] = ''
|
2026-05-23 21:14:49 +03:00
|
|
|
|
|
2026-05-25 18:19:13 +03:00
|
|
|
|
log_file.write(f"Найдено меток: {len(labels)}\n")
|
2026-05-23 21:14:49 +03:00
|
|
|
|
|
|
|
|
|
|
|
2026-05-25 18:19:13 +03:00
|
|
|
|
def reencode_instructions(entries, headers, log_file):
|
2026-05-23 08:52:52 +03:00
|
|
|
|
try:
|
|
|
|
|
|
source_with_values_idx = headers.index('команда_со_значениями')
|
|
|
|
|
|
calc_byte_idx = headers.index('рассчитанный_байт')
|
|
|
|
|
|
addr_idx = headers.index('адрес')
|
2026-05-23 18:56:43 +03:00
|
|
|
|
virt_addr_idx = headers.index('виртуальный_адрес')
|
2026-05-23 08:52:52 +03:00
|
|
|
|
byte_idx = headers.index('байт')
|
2026-05-23 21:14:49 +03:00
|
|
|
|
segment_idx = headers.index('сегмент')
|
2026-05-23 08:52:52 +03:00
|
|
|
|
except ValueError as e:
|
|
|
|
|
|
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
reencoded_count = 0
|
|
|
|
|
|
error_count = 0
|
|
|
|
|
|
|
|
|
|
|
|
i = 0
|
|
|
|
|
|
while i < len(entries):
|
|
|
|
|
|
row = entries[i]
|
|
|
|
|
|
addr_str = row[addr_idx].strip()
|
|
|
|
|
|
if not addr_str.startswith('0x'):
|
|
|
|
|
|
i += 1
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
file_addr = int(addr_str, 16)
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
# Берём виртуальный адрес инструкции из CSV
|
|
|
|
|
|
virt_addr_str = row[virt_addr_idx].strip()
|
|
|
|
|
|
if virt_addr_str.startswith('0x'):
|
|
|
|
|
|
instr_virt_addr = int(virt_addr_str, 16)
|
|
|
|
|
|
else:
|
|
|
|
|
|
instr_virt_addr = file_addr
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
cmd = row[source_with_values_idx].strip()
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
if cmd:
|
|
|
|
|
|
try:
|
|
|
|
|
|
mnemonic, operands = parse_command(cmd)
|
|
|
|
|
|
if mnemonic:
|
2026-05-25 18:19:13 +03:00
|
|
|
|
# Для отладки: записываем в лог все инструкции переместить_имм
|
|
|
|
|
|
if mnemonic == 'переместить_имм' and operands and '0x00403014' in cmd:
|
|
|
|
|
|
log_file.write(f"\nDEBUG MOV:\n")
|
|
|
|
|
|
log_file.write(f" Адрес в CSV: 0x{file_addr:08x}\n")
|
|
|
|
|
|
log_file.write(f" Команда: {cmd}\n")
|
|
|
|
|
|
log_file.write(f" Операнды: {operands}\n")
|
2026-05-23 18:56:43 +03:00
|
|
|
|
|
|
|
|
|
|
# Вычисляем current_pos как смещение в секции
|
2026-05-23 21:14:49 +03:00
|
|
|
|
section = row[segment_idx].strip()
|
|
|
|
|
|
|
|
|
|
|
|
if section == '.text':
|
2026-05-23 18:56:43 +03:00
|
|
|
|
current_pos = instr_virt_addr - vaddr_text
|
2026-05-23 21:14:49 +03:00
|
|
|
|
elif section == '.data':
|
2026-05-23 18:56:43 +03:00
|
|
|
|
current_pos = instr_virt_addr - vaddr_data
|
2026-05-23 21:14:49 +03:00
|
|
|
|
elif section == '.bss':
|
|
|
|
|
|
current_pos = instr_virt_addr - vaddr_bnd if vaddr_bnd else 0
|
2026-05-23 08:52:52 +03:00
|
|
|
|
else:
|
2026-05-25 18:19:13 +03:00
|
|
|
|
# Fallback: определяем по диапазону адресов - ФУФЛО, УБРАТЬ
|
2026-05-23 21:14:49 +03:00
|
|
|
|
if vaddr_text and 0x401000 <= instr_virt_addr < 0x402000:
|
|
|
|
|
|
current_pos = instr_virt_addr - vaddr_text
|
|
|
|
|
|
elif vaddr_data and 0x402000 <= instr_virt_addr < 0x403000:
|
|
|
|
|
|
current_pos = instr_virt_addr - vaddr_data
|
|
|
|
|
|
else:
|
|
|
|
|
|
current_pos = instr_virt_addr
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
encoded = encode_instruction(
|
|
|
|
|
|
mnemonic, operands, labels, label_sections, symbols,
|
2026-05-23 21:14:49 +03:00
|
|
|
|
vaddr_text, vaddr_data if vaddr_data else 0,
|
|
|
|
|
|
current_pos, vaddr_bnd if vaddr_bnd else 0
|
2026-05-23 08:52:52 +03:00
|
|
|
|
)
|
|
|
|
|
|
|
2026-05-25 18:19:13 +03:00
|
|
|
|
# Для отладки: записываем результат
|
|
|
|
|
|
if mnemonic == 'переместить_имм' and operands and '0x00403014' in cmd:
|
|
|
|
|
|
log_file.write(f" Закодировано: {[f'0x{b:02x}' for b in encoded]}\n")
|
|
|
|
|
|
log_file.write(f" Длина: {len(encoded)} байт\n")
|
2026-05-23 18:56:43 +03:00
|
|
|
|
|
2026-05-23 08:52:52 +03:00
|
|
|
|
for j, byte in enumerate(encoded):
|
|
|
|
|
|
if i + j < len(entries):
|
|
|
|
|
|
entries[i + j][calc_byte_idx] = f"0x{byte:02x}"
|
|
|
|
|
|
|
|
|
|
|
|
reencoded_count += 1
|
|
|
|
|
|
i += len(encoded)
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
2026-05-25 18:19:13 +03:00
|
|
|
|
log_file.write(f"\n=== ОШИБКА ===\n")
|
|
|
|
|
|
log_file.write(f" Команда: {cmd}\n")
|
|
|
|
|
|
log_file.write(f" Мнемоника: {mnemonic if 'mnemonic' in locals() else '?'}\n")
|
|
|
|
|
|
log_file.write(f" Ошибка: {e}\n")
|
2026-05-23 08:52:52 +03:00
|
|
|
|
error_count += 1
|
|
|
|
|
|
row[calc_byte_idx] = "0xcc"
|
|
|
|
|
|
i += 1
|
|
|
|
|
|
else:
|
2026-05-23 18:56:43 +03:00
|
|
|
|
# Если нет команды, копируем исходный байт
|
2026-05-23 08:52:52 +03:00
|
|
|
|
byte_str = row[byte_idx].strip()
|
|
|
|
|
|
if byte_str.startswith('0x'):
|
|
|
|
|
|
row[calc_byte_idx] = byte_str
|
|
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
|
|
|
|
return reencoded_count, error_count
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def save_csv(csv_file, headers, entries):
|
|
|
|
|
|
with open(csv_file, 'w', newline='', encoding='utf-8') as f:
|
|
|
|
|
|
writer = csv.writer(f, delimiter=';')
|
|
|
|
|
|
writer.writerow(headers)
|
|
|
|
|
|
writer.writerows(entries)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
def print_statistics(reencoded_count, error_count, labels_count):
|
2026-05-23 08:52:52 +03:00
|
|
|
|
print(f"\n--- Статистика перекодирования ---")
|
2026-05-23 18:56:43 +03:00
|
|
|
|
print(f" Меток в словаре: {labels_count}")
|
2026-05-23 08:52:52 +03:00
|
|
|
|
print(f" Перекодировано инструкций: {reencoded_count}")
|
|
|
|
|
|
if error_count:
|
|
|
|
|
|
print(f" Ошибок: {error_count}")
|
2026-05-23 18:56:43 +03:00
|
|
|
|
else:
|
|
|
|
|
|
print(f" Ошибок: нет")
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
|
if len(sys.argv) != 2:
|
|
|
|
|
|
print("Использование: python kvs_pass4.py <входной.csv>")
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
csv_file = sys.argv[1]
|
2026-05-25 18:19:13 +03:00
|
|
|
|
log_file_name = csv_file.replace('.csv', '_pass4.log')
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
print(f"\n=== Четвёртый проход КВС ===")
|
|
|
|
|
|
print(f"Чтение CSV: {csv_file}")
|
|
|
|
|
|
|
2026-05-25 18:19:13 +03:00
|
|
|
|
with open(log_file_name, 'w', encoding='utf-8') as log_file:
|
|
|
|
|
|
log_file.write(f"=== Четвёртый проход КВС ===\n")
|
|
|
|
|
|
log_file.write(f"CSV: {csv_file}\n\n")
|
|
|
|
|
|
|
|
|
|
|
|
headers, entries = read_csv(csv_file)
|
|
|
|
|
|
|
|
|
|
|
|
log_file.write(f"--- Определение адресов секций из CSV ---\n")
|
|
|
|
|
|
detect_section_addresses(entries, headers, log_file)
|
|
|
|
|
|
|
|
|
|
|
|
log_file.write(f"\n--- Сбор меток из CSV ---\n")
|
|
|
|
|
|
collect_labels_from_csv(entries, headers, log_file)
|
|
|
|
|
|
|
|
|
|
|
|
log_file.write(f"\n--- Перекодирование инструкций ---\n")
|
|
|
|
|
|
reencoded_count, error_count = reencode_instructions(entries, headers, log_file)
|
|
|
|
|
|
|
|
|
|
|
|
log_file.write(f"\n--- Статистика ---\n")
|
|
|
|
|
|
log_file.write(f" Меток в словаре: {len(labels)}\n")
|
|
|
|
|
|
log_file.write(f" Перекодировано инструкций: {reencoded_count}\n")
|
|
|
|
|
|
log_file.write(f" Ошибок: {error_count}\n")
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
print_statistics(reencoded_count, error_count, len(labels))
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
save_csv(csv_file, headers, entries)
|
2026-05-23 18:56:43 +03:00
|
|
|
|
print(f"\nCSV сохранён: {csv_file}")
|
2026-05-25 18:19:13 +03:00
|
|
|
|
print(f"Лог сохранён: {log_file_name}")
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
main()
|