kvs/kvs_pass4.py

244 lines
9.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Четвёртый проход КВС
- Перекодирует инструкции, используя подставленные значения
- Смотрит колонку 'команда_со_значениями'
- Записывает перекодированные байты в колонку 'рассчитанный_байт'
- Использует виртуальные адреса из CSV для вычисления смещений
"""
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
# ========== ГЛОБАЛЬНОЕ СОСТОЯНИЕ ==========
vaddr_text = text_vaddr_base
vaddr_data = 0x402000
vaddr_bnd = None
labels = {}
label_sections = {}
symbols = {}
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
def collect_labels_from_csv(entries, headers):
"""
Собирает метки из CSV, используя колонку 'виртуальный_адрес'
"""
global labels, label_sections
try:
label_idx = headers.index('приводящая_метка')
virt_addr_idx = headers.index('виртуальный_адрес')
except ValueError as e:
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
sys.exit(1)
for row in entries:
label_str = row[label_idx].strip()
if label_str:
virt_addr_str = row[virt_addr_idx].strip()
if virt_addr_str.startswith('0x'):
virt_addr = int(virt_addr_str, 16)
for label_name in label_str.split(','):
label_name = label_name.strip()
if label_name:
labels[label_name] = virt_addr
label_sections[label_name] = ''
def reencode_instructions(entries, headers):
try:
source_with_values_idx = headers.index('команда_со_значениями')
calc_byte_idx = headers.index('рассчитанный_байт')
addr_idx = headers.index('адрес')
virt_addr_idx = headers.index('виртуальный_адрес')
byte_idx = headers.index('байт')
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
file_addr = int(addr_str, 16)
# Берём виртуальный адрес инструкции из 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
cmd = row[source_with_values_idx].strip()
if cmd:
try:
mnemonic, operands = parse_command(cmd)
if mnemonic:
# ОТЛАДОЧНЫЙ ВЫВОД (только для переходов)
if mnemonic.startswith('короткий_переход') or mnemonic.startswith('переход'):
print(f"\n=== ОТЛАДКА ===")
print(f" Адрес в CSV: 0x{file_addr:08x}")
print(f" Виртуальный адрес инструкции: 0x{instr_virt_addr:08x}")
print(f" Команда: {cmd}")
print(f" Мнемоника: {mnemonic}")
print(f" Операнды: {operands}")
if operands and len(operands) > 0:
target_str = operands[0]
if target_str.startswith('0x'):
target_addr = int(target_str, 16)
# Определяем размер инструкции
if mnemonic.startswith('короткий'):
instr_size = 2
else:
instr_size = 5
offset = target_addr - (instr_virt_addr + instr_size)
print(f" Целевой адрес: 0x{target_addr:08x}")
print(f" Размер инструкции: {instr_size}")
print(f" RIP = 0x{instr_virt_addr + instr_size:08x}")
print(f" Смещение = {offset} (0x{offset & 0xFFFFFFFF:08x})")
print(f" В диапазоне [-128..127]: {-128 <= offset <= 127}")
# Вычисляем current_pos как смещение в секции
# Определяем секцию по виртуальному адресу
if 0x401000 <= instr_virt_addr < 0x402000:
current_pos = instr_virt_addr - vaddr_text
elif 0x402000 <= instr_virt_addr < 0x403000:
current_pos = instr_virt_addr - vaddr_data
else:
current_pos = instr_virt_addr
# Преобразуем операнды: если строка с 0x, оставляем как есть
# Кодировщик сам разберётся с isdigit()
encoded = encode_instruction(
mnemonic, operands, labels, label_sections, symbols,
vaddr_text, vaddr_data, current_pos, vaddr_bnd
)
if mnemonic.startswith('короткий_переход') or mnemonic.startswith('переход'):
print(f" Закодировано: {[f'0x{b:02x}' for b in encoded]}")
print(f" РЕЗУЛЬТАТ: УСПЕШНО")
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:
print(f"\n=== ОТЛАДКА (ОШИБКА) ===")
print(f" Команда: {cmd}")
print(f" Мнемоника: {mnemonic if 'mnemonic' in locals() else '?'}")
print(f" Операнды: {operands if 'operands' in locals() else '?'}")
print(f" Виртуальный адрес инструкции: 0x{instr_virt_addr:08x}")
print(f" ОШИБКА: {e}")
error_count += 1
row[calc_byte_idx] = "0xcc"
i += 1
else:
# Если нет команды, копируем исходный байт
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)
def print_statistics(reencoded_count, error_count, labels_count):
print(f"\n--- Статистика перекодирования ---")
print(f" Меток в словаре: {labels_count}")
print(f" Перекодировано инструкций: {reencoded_count}")
if error_count:
print(f" Ошибок: {error_count}")
else:
print(f" Ошибок: нет")
def main():
if len(sys.argv) != 2:
print("Использование: python kvs_pass4.py <входной.csv>")
sys.exit(1)
csv_file = sys.argv[1]
print(f"\n=== Четвёртый проход КВС ===")
print(f"Чтение CSV: {csv_file}")
headers, entries = read_csv(csv_file)
print(f"\n--- Сбор меток из CSV ---")
collect_labels_from_csv(entries, headers)
print(f"Найдено меток: {len(labels)}")
if labels:
print(f"\n--- Примеры меток (виртуальные адреса) ---")
for i, name in enumerate(sorted(labels.keys())[:10]):
print(f" {name} -> 0x{labels[name]:08x}")
if len(labels) > 10:
print(f" ... и ещё {len(labels) - 10}")
print(f"\n--- Перекодирование инструкций ---")
reencoded_count, error_count = reencode_instructions(entries, headers)
print_statistics(reencoded_count, error_count, len(labels))
save_csv(csv_file, headers, entries)
print(f"\nCSV сохранён: {csv_file}")
print(f"Колонка 'рассчитанный_байт' обновлена")
if __name__ == "__main__":
main()