#!/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()