1261 lines
45 KiB
Python
1261 lines
45 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
Второй проход КВС
|
||
Генерирует машинный код и создаёт CSV-файл
|
||
"""
|
||
|
||
import sys
|
||
import struct
|
||
sys.path.insert(0, '.')
|
||
from kvs_data import INSTRUCTIONS, REGISTERS, get_reg_info, PAGE_SIZE, align_up
|
||
|
||
|
||
def unescape_string(s):
|
||
"""Преобразует escape-последовательности в реальные символы"""
|
||
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])
|
||
result.append(s[i + 1])
|
||
i += 2
|
||
else:
|
||
result.append(s[i])
|
||
i += 1
|
||
return ''.join(result)
|
||
|
||
|
||
def read_ast(input_file):
|
||
"""Читает AST из файла"""
|
||
ast_lines = []
|
||
with open(input_file, 'r', encoding='utf-8') as f:
|
||
for line in f:
|
||
ast_lines.append(line.strip())
|
||
return ast_lines
|
||
|
||
|
||
def read_pass1(input_file):
|
||
"""
|
||
Читает результаты первого прохода:
|
||
- PARAM: параметры компоновки (размеры, адреса)
|
||
- LABEL: метки и их позиции
|
||
- SYMBOL: константы
|
||
"""
|
||
data = {}
|
||
labels = {}
|
||
label_sections = {}
|
||
symbols = {}
|
||
|
||
with open(input_file, 'r', encoding='utf-8') as f:
|
||
for line in f:
|
||
line = line.strip()
|
||
if not line:
|
||
continue
|
||
parts = line.split(':')
|
||
if parts[0] == "PARAM":
|
||
key = parts[1]
|
||
value = parts[2]
|
||
if value.isdigit():
|
||
value = int(value)
|
||
data[key] = value
|
||
elif parts[0] == "LABEL":
|
||
label = parts[1]
|
||
sec = parts[2]
|
||
pos = int(parts[3])
|
||
labels[label] = pos
|
||
label_sections[label] = sec
|
||
elif parts[0] == "SYMBOL":
|
||
name = parts[1]
|
||
value = int(parts[2])
|
||
symbols[name] = value
|
||
|
||
return data, labels, label_sections, symbols
|
||
|
||
|
||
def parse_operand(operand, labels, label_sections, symbols, vaddr_text, vaddr_data):
|
||
"""
|
||
Вычисляет значение операнда.
|
||
Поддерживает:
|
||
- десятичные числа (123)
|
||
- шестнадцатеричные (0x7B)
|
||
- метки (имя_метки)
|
||
- константы (из .константа)
|
||
"""
|
||
if operand.isdigit():
|
||
return int(operand)
|
||
if operand.startswith("0x"):
|
||
return int(operand, 16)
|
||
if operand in labels:
|
||
section = label_sections[operand]
|
||
base = vaddr_text if section == ".text" else vaddr_data
|
||
return labels[operand] + base
|
||
if operand in symbols:
|
||
return symbols[operand]
|
||
raise ValueError("Неизвестный операнд: " + operand)
|
||
|
||
|
||
# ========== ГЕНЕРАТОРЫ МАШИННОГО КОДА ДЛЯ КАЖДОЙ ГРУППЫ ИНСТРУКЦИЙ ==========
|
||
|
||
# ----- 1. Инструкции перемещения данных (MOV, LEA, MOVZX, MOVSX) -----
|
||
|
||
def encode_mov_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data):
|
||
"""
|
||
MOV reg, imm - переместить непосредственное значение в регистр
|
||
Формат: переместить_имм <регистр>, <значение|метка|константа>
|
||
"""
|
||
code = bytearray()
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
size = reg_info["size"]
|
||
imm = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
|
||
if size == 64:
|
||
if 0 <= reg <= 7:
|
||
code.extend(b'\x48')
|
||
code.append(0xB8 + reg)
|
||
elif 8 <= reg <= 15:
|
||
code.extend(b'\x49')
|
||
code.append(0xB8 + (reg - 8))
|
||
code.extend(struct.pack('<Q', imm & 0xFFFFFFFFFFFFFFFF))
|
||
elif size == 32:
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
if rex != 0x40:
|
||
code.append(rex)
|
||
code.append(0xC7)
|
||
modrm = 0xC0 | (reg & 7)
|
||
code.append(modrm)
|
||
code.extend(struct.pack('<I', imm & 0xFFFFFFFF))
|
||
elif size == 16:
|
||
code.append(0x66)
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
if rex != 0x40:
|
||
code.append(rex)
|
||
code.append(0xC7)
|
||
modrm = 0xC0 | (reg & 7)
|
||
code.append(modrm)
|
||
code.append(imm & 0xFF)
|
||
code.append((imm >> 8) & 0xFF)
|
||
elif size == 8:
|
||
if reg_info.get("high8"):
|
||
code.append(0xB0 + reg + 4)
|
||
else:
|
||
if reg < 4:
|
||
code.append(0xB0 + reg)
|
||
else:
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
code.append(rex)
|
||
code.append(0xB0 + (reg & 7))
|
||
code.append(imm & 0xFF)
|
||
|
||
return code
|
||
|
||
|
||
def encode_mov_reg_reg(operands):
|
||
"""
|
||
MOV reg, reg - переместить данные между регистрами
|
||
Формат: переместить <регистр_назначения>, <регистр_источник>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS["переместить"]
|
||
dst_info = get_reg_info(operands[0])
|
||
src_info = get_reg_info(operands[1])
|
||
dst = dst_info["index"]
|
||
src = src_info["index"]
|
||
size = dst_info["size"]
|
||
|
||
# Формируем REX префикс
|
||
use_66 = (size == 16)
|
||
use_rex_w = (size == 64)
|
||
rex = 0x40
|
||
if use_rex_w:
|
||
rex |= 0x08
|
||
if src >= 8:
|
||
rex |= 0x04
|
||
if dst >= 8:
|
||
rex |= 0x01
|
||
if dst_info.get("high8") or src_info.get("high8"):
|
||
rex = 0
|
||
|
||
if use_66:
|
||
code.append(0x66)
|
||
if rex != 0x40 or use_rex_w:
|
||
code.append(rex)
|
||
code.extend(instr["opcode"][-1:])
|
||
modrm = 0xC0 | ((src & 7) << 3) | (dst & 7)
|
||
code.append(modrm)
|
||
return code
|
||
|
||
|
||
def encode_mov_reg8_imm8(operands):
|
||
"""
|
||
MOV reg8, imm8 - загрузить непосредственный байт в 8-битный регистр
|
||
Формат: загрузить_байт <регистр8>, <байт>
|
||
"""
|
||
code = bytearray()
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
imm = int(operands[1]) if operands[1].isdigit() else int(operands[1], 16)
|
||
|
||
if reg_info.get("high8"):
|
||
code.append(0xB0 + reg + 4)
|
||
else:
|
||
if reg < 4:
|
||
code.append(0xB0 + reg)
|
||
else:
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
code.append(rex)
|
||
code.append(0xB0 + (reg & 7))
|
||
code.append(imm & 0xFF)
|
||
return code
|
||
|
||
|
||
def encode_lea(operands, labels, label_sections, symbols, vaddr_text, vaddr_data):
|
||
"""
|
||
LEA reg, mem - загрузить эффективный адрес
|
||
Формат: загрузить_адрес <регистр>, <адрес> (упрощённо - пока только метки)
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS["загрузить_адрес"]
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
addr = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
|
||
# Формируем REX префикс
|
||
rex = 0x48 if reg_info["size"] == 64 else 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
if rex != 0x40:
|
||
code.append(rex)
|
||
|
||
code.extend(instr["opcode"][-1:])
|
||
# ModR/M: mod=00 (disp32), reg=reg, r/m=101 (RIP-relative)
|
||
# Упрощённо: используем абсолютный адрес через disp32
|
||
modrm = 0x05 | ((reg & 7) << 3)
|
||
code.append(modrm)
|
||
code.extend(struct.pack('<i', addr))
|
||
return code
|
||
|
||
|
||
def encode_movzx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data):
|
||
"""
|
||
MOVZX reg, mem8 - переместить с расширением нулями
|
||
Формат: переместить_с_нулями <регистр>, <адрес_байта>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS["переместить_с_нулями"]
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
addr = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
|
||
rex = 0x48 if reg_info["size"] == 64 else 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
code.append(rex)
|
||
code.extend(instr["opcode"])
|
||
modrm = 0x05 | ((reg & 7) << 3)
|
||
code.append(modrm)
|
||
code.extend(struct.pack('<i', addr))
|
||
return code
|
||
|
||
|
||
def encode_movsx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data):
|
||
"""
|
||
MOVSX reg, mem8 - переместить с расширением знака
|
||
Формат: переместить_со_знаком <регистр>, <адрес_байта>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS["переместить_со_знаком"]
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
addr = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
|
||
rex = 0x48 if reg_info["size"] == 64 else 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
code.append(rex)
|
||
code.extend(instr["opcode"])
|
||
modrm = 0x05 | ((reg & 7) << 3)
|
||
code.append(modrm)
|
||
code.extend(struct.pack('<i', addr))
|
||
return code
|
||
|
||
|
||
# ----- 2. Инструкции сравнения (CMP, TEST) -----
|
||
|
||
def encode_cmp_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data):
|
||
"""
|
||
CMP reg, imm - сравнить регистр с непосредственным значением
|
||
Формат: сравнить_с <регистр>, <значение|метка|константа>
|
||
"""
|
||
code = bytearray()
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
size = reg_info["size"]
|
||
imm = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
|
||
if size == 64:
|
||
rex = 0x48
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
code.append(rex)
|
||
code.append(0x81)
|
||
modrm = 0xF8 | (reg & 7)
|
||
code.append(modrm)
|
||
code.extend(struct.pack('<i', imm))
|
||
elif size == 32:
|
||
if -128 <= imm <= 127:
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
if rex != 0x40:
|
||
code.append(rex)
|
||
code.append(0x83)
|
||
modrm = 0xF8 | (reg & 7)
|
||
code.append(modrm)
|
||
code.append(imm & 0xFF)
|
||
else:
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
if rex != 0x40:
|
||
code.append(rex)
|
||
code.append(0x81)
|
||
modrm = 0xF8 | (reg & 7)
|
||
code.append(modrm)
|
||
code.extend(struct.pack('<I', imm & 0xFFFFFFFF))
|
||
elif size == 16:
|
||
code.append(0x66)
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
if rex != 0x40:
|
||
code.append(rex)
|
||
code.append(0x81)
|
||
modrm = 0xF8 | (reg & 7)
|
||
code.append(modrm)
|
||
code.extend(struct.pack('<H', imm & 0xFFFF))
|
||
elif size == 8:
|
||
if reg_info.get("high8"):
|
||
code.append(0x80)
|
||
modrm = 0xF8 | reg
|
||
code.append(modrm)
|
||
else:
|
||
if reg < 4:
|
||
code.append(0x80)
|
||
modrm = 0xF8 | reg
|
||
code.append(modrm)
|
||
else:
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
code.append(rex)
|
||
code.append(0x80)
|
||
modrm = 0xF8 | (reg & 7)
|
||
code.append(modrm)
|
||
code.append(imm & 0xFF)
|
||
|
||
return code
|
||
|
||
|
||
def encode_cmp_reg_reg(mnemonic, operands):
|
||
"""
|
||
CMP reg, reg - сравнить регистры
|
||
Формат: сравнить <регистр1>, <регистр2>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS[mnemonic]
|
||
dst_info = get_reg_info(operands[0])
|
||
src_info = get_reg_info(operands[1])
|
||
dst = dst_info["index"]
|
||
src = src_info["index"]
|
||
size = dst_info["size"]
|
||
|
||
use_66 = (size == 16)
|
||
use_rex_w = (size == 64)
|
||
rex = 0x40
|
||
if use_rex_w:
|
||
rex |= 0x08
|
||
if src >= 8:
|
||
rex |= 0x04
|
||
if dst >= 8:
|
||
rex |= 0x01
|
||
if dst_info.get("high8") or src_info.get("high8"):
|
||
rex = 0
|
||
|
||
if use_66:
|
||
code.append(0x66)
|
||
if rex != 0x40 or use_rex_w:
|
||
code.append(rex)
|
||
code.extend(instr["opcode"][-1:])
|
||
modrm = 0xC0 | ((src & 7) << 3) | (dst & 7)
|
||
code.append(modrm)
|
||
return code
|
||
|
||
|
||
# ----- 3. Арифметические инструкции (ADD, SUB, MUL, DIV) -----
|
||
|
||
def encode_add_sub_reg_imm(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data):
|
||
"""
|
||
ADD/SUB reg, imm - прибавить/вычесть непосредственное значение
|
||
Формат: прибавить_непосредственно / вычесть_непосредственно <регистр>, <значение>
|
||
"""
|
||
code = bytearray()
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
size = reg_info["size"]
|
||
imm = parse_operand(operands[1], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
|
||
op_map = {
|
||
"прибавить_непосредственно": 0x81,
|
||
"вычесть_непосредственно": 0x81,
|
||
}
|
||
op = op_map.get(mnemonic, 0x81)
|
||
subop = 0 if mnemonic == "прибавить_непосредственно" else 5 # /0 для ADD, /5 для SUB
|
||
|
||
if size == 64:
|
||
rex = 0x48
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
code.append(rex)
|
||
code.append(op)
|
||
modrm = 0xC0 | (subop << 3) | (reg & 7)
|
||
code.append(modrm)
|
||
code.extend(struct.pack('<i', imm))
|
||
elif size == 32:
|
||
if -128 <= imm <= 127:
|
||
op = 0x83 # короткая форма
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
if rex != 0x40:
|
||
code.append(rex)
|
||
code.append(op)
|
||
modrm = 0xC0 | (subop << 3) | (reg & 7)
|
||
code.append(modrm)
|
||
code.append(imm & 0xFF)
|
||
else:
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
if rex != 0x40:
|
||
code.append(rex)
|
||
code.append(op)
|
||
modrm = 0xC0 | (subop << 3) | (reg & 7)
|
||
code.append(modrm)
|
||
code.extend(struct.pack('<I', imm & 0xFFFFFFFF))
|
||
elif size == 16:
|
||
code.append(0x66)
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
if rex != 0x40:
|
||
code.append(rex)
|
||
code.append(op)
|
||
modrm = 0xC0 | (subop << 3) | (reg & 7)
|
||
code.append(modrm)
|
||
code.extend(struct.pack('<H', imm & 0xFFFF))
|
||
|
||
return code
|
||
|
||
|
||
def encode_add_sub_reg_reg(mnemonic, operands):
|
||
"""
|
||
ADD/SUB reg, reg - сложить/вычесть регистры
|
||
Формат: прибавить / вычесть <регистр_назначения>, <регистр_источник>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS[mnemonic]
|
||
dst_info = get_reg_info(operands[0])
|
||
src_info = get_reg_info(operands[1])
|
||
dst = dst_info["index"]
|
||
src = src_info["index"]
|
||
size = dst_info["size"]
|
||
|
||
use_66 = (size == 16)
|
||
use_rex_w = (size == 64)
|
||
rex = 0x40
|
||
if use_rex_w:
|
||
rex |= 0x08
|
||
if src >= 8:
|
||
rex |= 0x04
|
||
if dst >= 8:
|
||
rex |= 0x01
|
||
if dst_info.get("high8") or src_info.get("high8"):
|
||
rex = 0
|
||
|
||
if use_66:
|
||
code.append(0x66)
|
||
if rex != 0x40 or use_rex_w:
|
||
code.append(rex)
|
||
code.extend(instr["opcode"][-1:])
|
||
modrm = 0xC0 | ((src & 7) << 3) | (dst & 7)
|
||
code.append(modrm)
|
||
return code
|
||
|
||
|
||
def encode_muldiv(mnemonic):
|
||
"""
|
||
MUL/IMUL/DIV/IDIV - умножение и деление (работают с RAX/RDX)
|
||
Формат: умножить / умножить_знаковое / разделить / разделить_знаковое
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS[mnemonic]
|
||
subop = instr["subop"]
|
||
|
||
code.append(0x48) # REX.W для 64-бит
|
||
code.extend(instr["opcode"])
|
||
modrm = 0xC0 | (subop << 3) | 0 # операнд в регистре (например, RBX, RCX)
|
||
code.append(modrm)
|
||
return code
|
||
|
||
|
||
# ----- 4. Логические инструкции (AND, OR, XOR, NOT, NEG) -----
|
||
|
||
def encode_and_or_xor_reg_reg(mnemonic, operands):
|
||
"""
|
||
AND/OR/XOR reg, reg - логические операции над регистрами
|
||
Формат: и / или / исключающее_или <регистр_назначения>, <регистр_источник>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS[mnemonic]
|
||
dst_info = get_reg_info(operands[0])
|
||
src_info = get_reg_info(operands[1])
|
||
dst = dst_info["index"]
|
||
src = src_info["index"]
|
||
size = dst_info["size"]
|
||
|
||
use_66 = (size == 16)
|
||
use_rex_w = (size == 64)
|
||
rex = 0x40
|
||
if use_rex_w:
|
||
rex |= 0x08
|
||
if src >= 8:
|
||
rex |= 0x04
|
||
if dst >= 8:
|
||
rex |= 0x01
|
||
if dst_info.get("high8") or src_info.get("high8"):
|
||
rex = 0
|
||
|
||
if use_66:
|
||
code.append(0x66)
|
||
if rex != 0x40 or use_rex_w:
|
||
code.append(rex)
|
||
code.extend(instr["opcode"][-1:])
|
||
modrm = 0xC0 | ((src & 7) << 3) | (dst & 7)
|
||
code.append(modrm)
|
||
return code
|
||
|
||
|
||
def encode_not_neg(mnemonic, operands):
|
||
"""
|
||
NOT/NEG - инвертировать/отрицать регистр
|
||
Формат: инвертировать / отрицать <регистр>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS[mnemonic]
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
size = reg_info["size"]
|
||
subop = instr["subop"]
|
||
|
||
if size == 64:
|
||
code.append(0x48)
|
||
elif size == 16:
|
||
code.append(0x66)
|
||
|
||
if reg >= 8:
|
||
code.append(0x41)
|
||
|
||
code.extend(instr["opcode"])
|
||
modrm = 0xC0 | (subop << 3) | (reg & 7)
|
||
code.append(modrm)
|
||
return code
|
||
|
||
|
||
# ----- 5. Инструкции переходов и вызовов (JMP, Jcc, CALL, RET, LOOP) -----
|
||
|
||
def encode_jmp_rel32(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
|
||
"""
|
||
JMP rel32 - безусловный переход с 32-битным смещением
|
||
Формат: переход <метка>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS["переход"]
|
||
code.extend(instr["opcode"])
|
||
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
offset = target - (vaddr_text + current_pos + 5)
|
||
code.extend(struct.pack('<i', offset))
|
||
return code
|
||
|
||
|
||
def encode_jmp_short(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
|
||
"""
|
||
JMP SHORT - короткий безусловный переход с 8-битным смещением
|
||
Формат: короткий_переход <метка>
|
||
"""
|
||
code = bytearray()
|
||
code.append(0xEB)
|
||
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
offset = target - (vaddr_text + current_pos + 2)
|
||
if not (-128 <= offset <= 127):
|
||
raise ValueError(f"Смещение короткого перехода {offset} вне диапазона [-128..127]")
|
||
code.append(offset & 0xFF)
|
||
return code
|
||
|
||
|
||
def encode_jcc_rel32(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
|
||
"""
|
||
Jcc rel32 - условный переход с 32-битным смещением
|
||
Формат: переход_если_... <метка>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS[mnemonic]
|
||
code.extend(instr["opcode"])
|
||
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
offset = target - (vaddr_text + current_pos + 6)
|
||
code.extend(struct.pack('<i', offset))
|
||
return code
|
||
|
||
|
||
def encode_jcc_short(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
|
||
"""
|
||
Jcc SHORT - короткий условный переход с 8-битным смещением
|
||
Формат: короткий_переход_если_... <метка>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS[mnemonic]
|
||
code.extend(instr["opcode"])
|
||
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
offset = target - (vaddr_text + current_pos + 2)
|
||
if not (-128 <= offset <= 127):
|
||
raise ValueError(f"Смещение короткого перехода {offset} вне диапазона [-128..127]")
|
||
code.append(offset & 0xFF)
|
||
return code
|
||
|
||
|
||
def encode_call(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
|
||
"""
|
||
CALL rel32 - вызов процедуры
|
||
Формат: вызвать <метка>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS["вызвать"]
|
||
code.extend(instr["opcode"])
|
||
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
offset = target - (vaddr_text + current_pos + 5)
|
||
code.extend(struct.pack('<i', offset))
|
||
return code
|
||
|
||
|
||
def encode_ret():
|
||
"""RET - возврат из процедуры"""
|
||
return INSTRUCTIONS["вернуться"]["opcode"]
|
||
|
||
|
||
def encode_loop(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
|
||
"""
|
||
LOOP rel8 - инструкция цикла
|
||
Формат: цикл <метка>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS["цикл"]
|
||
code.extend(instr["opcode"])
|
||
target = parse_operand(operands[0], labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
offset = target - (vaddr_text + current_pos + 2)
|
||
if not (-128 <= offset <= 127):
|
||
raise ValueError(f"Смещение LOOP {offset} вне диапазона [-128..127]")
|
||
code.append(offset & 0xFF)
|
||
return code
|
||
|
||
|
||
# ----- 6. Стековые инструкции (PUSH, POP) -----
|
||
|
||
def encode_push_reg(operands):
|
||
"""
|
||
PUSH reg - поместить регистр в стек
|
||
Формат: втолкнуть <регистр>
|
||
"""
|
||
code = bytearray()
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
size = reg_info["size"]
|
||
|
||
if size == 64:
|
||
if reg < 8:
|
||
code.append(0x50 + reg)
|
||
else:
|
||
code.append(0x41)
|
||
code.append(0x50 + (reg - 8))
|
||
elif size == 16:
|
||
code.append(0x66)
|
||
if reg < 8:
|
||
code.append(0x50 + reg)
|
||
else:
|
||
code.append(0x41)
|
||
code.append(0x50 + (reg - 8))
|
||
else:
|
||
raise ValueError(f"PUSH не поддерживает {size}-битные регистры")
|
||
|
||
return code
|
||
|
||
|
||
def encode_pop_reg(operands):
|
||
"""
|
||
POP reg - извлечь из стека в регистр
|
||
Формат: вытолкнуть <регистр>
|
||
"""
|
||
code = bytearray()
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
size = reg_info["size"]
|
||
|
||
if size == 64:
|
||
if reg < 8:
|
||
code.append(0x58 + reg)
|
||
else:
|
||
code.append(0x41)
|
||
code.append(0x58 + (reg - 8))
|
||
elif size == 16:
|
||
code.append(0x66)
|
||
if reg < 8:
|
||
code.append(0x58 + reg)
|
||
else:
|
||
code.append(0x41)
|
||
code.append(0x58 + (reg - 8))
|
||
else:
|
||
raise ValueError(f"POP не поддерживает {size}-битные регистры")
|
||
|
||
return code
|
||
|
||
|
||
def encode_push_imm(operands):
|
||
"""
|
||
PUSH imm - поместить непосредственное значение в стек
|
||
Формат: втолкнуть_непосредственно <значение>
|
||
"""
|
||
code = bytearray()
|
||
imm = int(operands[0]) if operands[0].isdigit() else int(operands[0], 16)
|
||
|
||
if -128 <= imm <= 127:
|
||
code.append(0x6A) # PUSH imm8
|
||
code.append(imm & 0xFF)
|
||
else:
|
||
code.append(0x68) # PUSH imm32
|
||
code.extend(struct.pack('<i', imm))
|
||
|
||
return code
|
||
|
||
|
||
|
||
# ----- 7. Битовые операции (SHL, SHR, SAR, ROL, ROR) -----
|
||
|
||
def encode_shift_rotate(mnemonic, operands):
|
||
"""
|
||
SHL/SHR/SAR/ROL/ROR - сдвиги и вращения
|
||
Формат: сдвиг_влево <регистр>, <количество>
|
||
"""
|
||
code = bytearray()
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
size = reg_info["size"]
|
||
shift = int(operands[1]) if operands[1].isdigit() else int(operands[1], 16)
|
||
|
||
# REX.W только для 64-битных регистров
|
||
if size == 64:
|
||
code.append(0x48)
|
||
|
||
# Опкод C1 для сдвига с imm8
|
||
code.append(0xC1)
|
||
|
||
# subop в зависимости от типа
|
||
subop_map = {
|
||
"сдвиг_влево": 4, # SHL = /4
|
||
"сдвиг_вправо": 5, # SHR = /5
|
||
"сдвиг_арифметический_вправо": 7, # SAR = /7
|
||
"вращать_влево": 0, # ROL = /0
|
||
"вращать_вправо": 1, # ROR = /1
|
||
}
|
||
subop = subop_map.get(mnemonic, 0)
|
||
|
||
# ModR/M: mod=11, reg=subop, r/m=reg
|
||
modrm = 0xC0 | (subop << 3) | (reg & 7)
|
||
code.append(modrm)
|
||
code.append(shift & 0xFF)
|
||
|
||
return bytes(code)
|
||
# ----- 8. Системные и отладочные инструкции -----
|
||
|
||
def encode_syscall():
|
||
"""SYSCALL - системный вызов"""
|
||
return INSTRUCTIONS["вызов_системы"]["opcode"]
|
||
|
||
|
||
def encode_int(operands):
|
||
"""
|
||
INT imm8 - прерывание
|
||
Формат: прервать <номер>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS["прервать"]
|
||
code.extend(instr["opcode"])
|
||
imm = int(operands[0]) if operands[0].isdigit() else int(operands[0], 16)
|
||
code.append(imm & 0xFF)
|
||
return code
|
||
|
||
|
||
def encode_hlt():
|
||
"""HLT - остановить процессор"""
|
||
return INSTRUCTIONS["остановить"]["opcode"]
|
||
|
||
|
||
def encode_int3():
|
||
"""INT3 - точка останова (отладка)"""
|
||
return INSTRUCTIONS["отладка"]["opcode"]
|
||
|
||
|
||
def encode_nop():
|
||
"""NOP - нет операции"""
|
||
return INSTRUCTIONS["нет_операции"]["opcode"]
|
||
|
||
|
||
# ----- 9. Инструкции работы с флагами -----
|
||
|
||
def encode_flag_instruction(mnemonic):
|
||
"""STC/CLC/STD/CLD/PUSHF/POPF - инструкции работы с флагами"""
|
||
return INSTRUCTIONS[mnemonic]["opcode"]
|
||
|
||
|
||
# ----- 10. Ввод-вывод -----
|
||
|
||
def encode_in(operands):
|
||
"""
|
||
IN imm8 - ввод байта из порта
|
||
Формат: ввод_байта <порт>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS["ввод_байта"]
|
||
code.extend(instr["opcode"])
|
||
port = int(operands[0]) if operands[0].isdigit() else int(operands[0], 16)
|
||
code.append(port & 0xFF)
|
||
return code
|
||
|
||
|
||
def encode_out(operands):
|
||
"""
|
||
OUT imm8 - вывод байта в порт
|
||
Формат: вывод_байта <порт>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS["вывод_байта"]
|
||
code.extend(instr["opcode"])
|
||
port = int(operands[0]) if operands[0].isdigit() else int(operands[0], 16)
|
||
code.append(port & 0xFF)
|
||
return code
|
||
|
||
|
||
# ----- 11. Строковые инструкции -----
|
||
|
||
def encode_string_instruction(mnemonic):
|
||
"""MOVSB/MOVSW/CMPSB/SCASB - строковые инструкции"""
|
||
return INSTRUCTIONS[mnemonic]["opcode"]
|
||
|
||
|
||
# ----- 12. Инструкции идентификации процессора -----
|
||
|
||
def encode_cpuid():
|
||
"""CPUID - идентификация процессора"""
|
||
return INSTRUCTIONS["идентифицировать_процессор"]["opcode"]
|
||
|
||
|
||
def encode_rdtsc():
|
||
"""RDTSC - чтение счётчика времени"""
|
||
return INSTRUCTIONS["прочитать_счётчик"]["opcode"]
|
||
|
||
|
||
# ----- 13. Инструкции с памятью (упрощённые) -----
|
||
|
||
def encode_xchg(operands):
|
||
"""
|
||
XCHG reg, reg - обменять регистры
|
||
Формат: обменять <регистр1>, <регистр2>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS["обменять"]
|
||
reg1_info = get_reg_info(operands[0])
|
||
reg2_info = get_reg_info(operands[1])
|
||
reg1 = reg1_info["index"]
|
||
reg2 = reg2_info["index"]
|
||
|
||
rex = 0x48 if reg1_info["size"] == 64 else 0x40
|
||
if reg1 >= 8 or reg2 >= 8:
|
||
rex |= 0x01
|
||
if reg2 >= 8:
|
||
rex |= 0x04
|
||
code.append(rex)
|
||
code.extend(instr["opcode"])
|
||
modrm = 0xC0 | ((reg2 & 7) << 3) | (reg1 & 7)
|
||
code.append(modrm)
|
||
return code
|
||
|
||
|
||
# ========== ГЛАВНЫЙ ДИСПЕТЧЕР ==========
|
||
|
||
def encode_instruction(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
|
||
"""
|
||
Главный диспетчер генерации машинного кода.
|
||
По мнемонике выбирает соответствующую функцию генерации.
|
||
"""
|
||
|
||
# ----- Инструкции без операндов -----
|
||
if mnemonic == "вызов_системы":
|
||
return encode_syscall()
|
||
elif mnemonic == "нет_операции":
|
||
return encode_nop()
|
||
elif mnemonic == "вернуться":
|
||
return encode_ret()
|
||
elif mnemonic == "остановить":
|
||
return encode_hlt()
|
||
elif mnemonic == "отладка":
|
||
return encode_int3()
|
||
elif mnemonic in ("установить_перенос", "сбросить_перенос", "установить_направление",
|
||
"сбросить_направление", "втолкнуть_флаги", "вытолкнуть_флаги"):
|
||
return encode_flag_instruction(mnemonic)
|
||
elif mnemonic in ("переместить_байт", "переместить_слово", "сравнить_байты", "сканировать_байт"):
|
||
return encode_string_instruction(mnemonic)
|
||
elif mnemonic == "идентифицировать_процессор":
|
||
return encode_cpuid()
|
||
elif mnemonic == "прочитать_счётчик":
|
||
return encode_rdtsc()
|
||
|
||
# ----- MOV (разные формы) -----
|
||
elif mnemonic == "переместить_имм":
|
||
return encode_mov_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
elif mnemonic == "переместить":
|
||
return encode_mov_reg_reg(operands)
|
||
elif mnemonic == "загрузить_байт":
|
||
return encode_mov_reg8_imm8(operands)
|
||
elif mnemonic == "загрузить_адрес":
|
||
return encode_lea(operands, labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
elif mnemonic == "переместить_с_нулями":
|
||
return encode_movzx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
elif mnemonic == "переместить_со_знаком":
|
||
return encode_movsx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
|
||
# ----- CMP (сравнение) -----
|
||
elif mnemonic == "сравнить_с":
|
||
return encode_cmp_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
elif mnemonic in ("сравнить", "сравнить_байт", "проверить"):
|
||
return encode_cmp_reg_reg(mnemonic, operands)
|
||
|
||
# ----- ADD/SUB (арифметика) -----
|
||
elif mnemonic in ("прибавить_непосредственно", "вычесть_непосредственно"):
|
||
return encode_add_sub_reg_imm(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data)
|
||
elif mnemonic in ("прибавить", "вычесть", "прибавить_байт", "вычесть_байт"):
|
||
return encode_add_sub_reg_reg(mnemonic, operands)
|
||
|
||
# ----- MUL/DIV -----
|
||
elif mnemonic in ("умножить", "умножить_знаковое", "разделить", "разделить_знаковое"):
|
||
return encode_muldiv(mnemonic)
|
||
|
||
# ----- AND/OR/XOR -----
|
||
elif mnemonic in ("и", "или", "исключающее_или"):
|
||
return encode_and_or_xor_reg_reg(mnemonic, operands)
|
||
|
||
# ----- NOT/NEG -----
|
||
elif mnemonic in ("инвертировать", "отрицать"):
|
||
return encode_not_neg(mnemonic, operands)
|
||
|
||
# ----- INC/DEC -----
|
||
elif mnemonic in ("увеличить", "уменьшить"):
|
||
return encode_incdec(mnemonic, operands)
|
||
|
||
# ----- Переходы -----
|
||
elif mnemonic == "переход":
|
||
return encode_jmp_rel32(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
|
||
elif mnemonic == "короткий_переход":
|
||
return encode_jmp_short(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
|
||
elif mnemonic in ("переход_если_равно", "переход_если_неравно", "переход_если_меньше",
|
||
"переход_если_больше", "переход_если_меньше_или_равно", "переход_если_больше_или_равно",
|
||
"переход_если_перенос", "переход_если_нет_переноса", "переход_если_ноль", "переход_если_не_ноль"):
|
||
return encode_jcc_rel32(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
|
||
elif mnemonic in ("короткий_переход_если_равно", "короткий_переход_если_неравно",
|
||
"короткий_переход_если_меньше", "короткий_переход_если_больше",
|
||
"короткий_переход_если_меньше_или_равно", "короткий_переход_если_больше_или_равно",
|
||
"короткий_переход_если_перенос", "короткий_переход_если_нет_переноса",
|
||
"короткий_переход_если_ноль", "короткий_переход_если_не_ноль"):
|
||
return encode_jcc_short(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
|
||
|
||
# ----- CALL/RET/LOOP -----
|
||
elif mnemonic == "вызвать":
|
||
return encode_call(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
|
||
elif mnemonic == "цикл":
|
||
return encode_loop(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
|
||
|
||
# ----- PUSH/POP -----
|
||
elif mnemonic == "втолкнуть":
|
||
return encode_push_reg(operands)
|
||
elif mnemonic == "вытолкнуть":
|
||
return encode_pop_reg(operands)
|
||
elif mnemonic == "втолкнуть_непосредственно":
|
||
return encode_push_imm(operands)
|
||
|
||
# ----- Битовые операции -----
|
||
elif mnemonic in ("сдвиг_влево", "сдвиг_вправо", "сдвиг_арифметический_вправо",
|
||
"вращать_влево", "вращать_вправо"):
|
||
return encode_shift_rotate(mnemonic, operands)
|
||
|
||
# ----- Ввод-вывод -----
|
||
elif mnemonic == "ввод_байта":
|
||
return encode_in(operands)
|
||
elif mnemonic == "вывод_байта":
|
||
return encode_out(operands)
|
||
|
||
# ----- Прочие -----
|
||
elif mnemonic == "прервать":
|
||
return encode_int(operands)
|
||
elif mnemonic == "обменять":
|
||
return encode_xchg(operands)
|
||
|
||
else:
|
||
raise NotImplementedError(f"Инструкция '{mnemonic}' не реализована")
|
||
|
||
|
||
def encode_incdec(mnemonic, operands):
|
||
"""
|
||
INC / DEC - инкремент и декремент регистра
|
||
Формат: увеличить <регистр> / уменьшить <регистр>
|
||
"""
|
||
code = bytearray()
|
||
instr = INSTRUCTIONS[mnemonic]
|
||
reg_info = get_reg_info(operands[0])
|
||
reg = reg_info["index"]
|
||
size = reg_info["size"]
|
||
subop = instr["subop"]
|
||
|
||
if size == 64:
|
||
rex = 0x48
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
code.append(rex)
|
||
code.append(0xFF)
|
||
elif size == 32:
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
if rex != 0x40:
|
||
code.append(rex)
|
||
code.append(0xFF)
|
||
elif size == 16:
|
||
code.append(0x66)
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
if rex != 0x40:
|
||
code.append(rex)
|
||
code.append(0xFF)
|
||
elif size == 8:
|
||
if reg_info.get("high8"):
|
||
code.append(0xFE)
|
||
else:
|
||
if reg < 4:
|
||
code.append(0xFE)
|
||
else:
|
||
rex = 0x40
|
||
if reg >= 8:
|
||
rex |= 0x01
|
||
code.append(rex)
|
||
code.append(0xFE)
|
||
modrm = 0xC0 | (subop << 3) | (reg & 7)
|
||
code.append(modrm)
|
||
return bytes(code)
|
||
|
||
modrm = 0xC0 | (subop << 3) | (reg & 7)
|
||
code.append(modrm)
|
||
return bytes(code)
|
||
|
||
|
||
# ========== ОСНОВНОЙ КЛАСС ВТОРОГО ПРОХОДА ==========
|
||
|
||
class Pass2:
|
||
def __init__(self, pass1_data, labels, label_sections, symbols):
|
||
self.labels = labels
|
||
self.label_sections = label_sections
|
||
self.symbols = symbols
|
||
self.vaddr_text = pass1_data["vaddr_text"]
|
||
text_size = pass1_data["text_size"]
|
||
self.vaddr_data = align_up(self.vaddr_text + text_size, PAGE_SIZE)
|
||
self.position = {".text": 0, ".data": 0}
|
||
self.current_section = ".text"
|
||
self.csv_lines = []
|
||
self.data_bytes = {".text": bytearray(), ".data": bytearray()}
|
||
|
||
def get_target_addr(self, mnemonic, operands):
|
||
"""Вычисляет целевой адрес для инструкций перехода"""
|
||
jump_instructions = {
|
||
"переход", "короткий_переход", "вызвать", "цикл",
|
||
"переход_если_равно", "переход_если_неравно", "переход_если_меньше",
|
||
"переход_если_больше", "переход_если_меньше_или_равно", "переход_если_больше_или_равно",
|
||
"переход_если_перенос", "переход_если_нет_переноса", "переход_если_ноль", "переход_если_не_ноль",
|
||
"короткий_переход_если_равно", "короткий_переход_если_неравно", "короткий_переход_если_меньше",
|
||
"короткий_переход_если_больше", "короткий_переход_если_меньше_или_равно", "короткий_переход_если_больше_или_равно",
|
||
"короткий_переход_если_перенос", "короткий_переход_если_нет_переноса",
|
||
"короткий_переход_если_ноль", "короткий_переход_если_не_ноль"
|
||
}
|
||
|
||
try:
|
||
if mnemonic in jump_instructions:
|
||
target = parse_operand(operands[0], self.labels, self.label_sections,
|
||
self.symbols, self.vaddr_text, self.vaddr_data)
|
||
return hex(target)
|
||
elif mnemonic == "переместить_имм" and len(operands) >= 2:
|
||
op_str = operands[1]
|
||
if op_str in self.labels:
|
||
sec = self.label_sections[op_str]
|
||
addr = self.labels[op_str] + (self.vaddr_text if sec == ".text" else self.vaddr_data)
|
||
return hex(addr)
|
||
elif op_str in self.symbols:
|
||
return hex(self.symbols[op_str])
|
||
except Exception:
|
||
return "ошибка"
|
||
|
||
return ""
|
||
|
||
def process_line(self, line):
|
||
"""Обрабатывает одну строку AST"""
|
||
parts = line.split(':')
|
||
line_type = parts[0]
|
||
|
||
if line_type == "DIRECTIVE":
|
||
directive = parts[1]
|
||
if directive == '.текст':
|
||
self.current_section = ".text"
|
||
elif directive == '.данные':
|
||
self.current_section = ".data"
|
||
elif directive in ('.строка_нуль', '.строка'):
|
||
s = parts[3] if len(parts) > 3 else ""
|
||
real_s = unescape_string(s)
|
||
bstring = real_s.encode('utf-8')
|
||
if directive == '.строка_нуль':
|
||
bstring += b'\x00'
|
||
|
||
original_cmd = f'{directive} "{s}"'
|
||
start_addr = self.vaddr_data + self.position[".data"]
|
||
|
||
for i, byte in enumerate(bstring):
|
||
addr = start_addr + i
|
||
byte_hex = "{:02X}".format(byte)
|
||
cmd = original_cmd if i == 0 else ""
|
||
self.csv_lines.append((hex(addr), byte_hex, "", cmd))
|
||
|
||
self.data_bytes[".data"] += bstring
|
||
self.position[".data"] += len(bstring)
|
||
|
||
elif directive == '.байт':
|
||
if len(parts) > 3 and parts[3]:
|
||
bytes_str = parts[3]
|
||
byte_values = bytes_str.split(',')
|
||
original_cmd = f".байт {bytes_str}"
|
||
start_addr = self.vaddr_data + self.position[".data"]
|
||
|
||
for i, byte_str in enumerate(byte_values):
|
||
if byte_str.startswith('0x'):
|
||
val = int(byte_str, 16)
|
||
elif byte_str.isdigit() or (byte_str.startswith('-') and byte_str[1:].isdigit()):
|
||
val = int(byte_str)
|
||
else:
|
||
continue
|
||
|
||
addr = start_addr + i
|
||
byte_hex = "{:02X}".format(val & 0xFF)
|
||
cmd = original_cmd if i == 0 else ""
|
||
self.csv_lines.append((hex(addr), byte_hex, "", cmd))
|
||
self.data_bytes[".data"].append(val & 0xFF)
|
||
|
||
self.position[".data"] += len(byte_values)
|
||
|
||
elif line_type == "LABEL":
|
||
label_name = parts[1]
|
||
sec = parts[2]
|
||
if label_name in self.labels:
|
||
self.position[sec] = self.labels[label_name]
|
||
|
||
elif line_type == "INSTR":
|
||
mnemonic = parts[1]
|
||
sec = parts[2]
|
||
|
||
operands = []
|
||
if len(parts) > 3 and parts[3]:
|
||
operands = parts[3].split(',')
|
||
|
||
if operands:
|
||
original_cmd = f"{mnemonic} {', '.join(operands)}"
|
||
else:
|
||
original_cmd = mnemonic
|
||
|
||
current_pos = self.position[sec]
|
||
code = encode_instruction(mnemonic, operands, self.labels, self.label_sections,
|
||
self.symbols, self.vaddr_text, self.vaddr_data, current_pos)
|
||
|
||
target_addr = self.get_target_addr(mnemonic, operands)
|
||
|
||
start_addr = (self.vaddr_text if sec == ".text" else self.vaddr_data) + current_pos
|
||
|
||
for i, byte in enumerate(code):
|
||
addr = start_addr + i
|
||
byte_hex = "{:02X}".format(byte)
|
||
cmd = original_cmd if i == 0 else ""
|
||
addr_target = target_addr if i == 0 else ""
|
||
self.csv_lines.append((hex(addr), byte_hex, addr_target, cmd))
|
||
|
||
self.data_bytes[sec] += code
|
||
self.position[sec] += len(code)
|
||
|
||
def process_all(self, ast_lines):
|
||
"""Обрабатывает все строки AST"""
|
||
for line in ast_lines:
|
||
self.process_line(line)
|
||
return self.csv_lines
|
||
|
||
|
||
def write_csv(csv_lines, output_file):
|
||
"""Записывает сгенерированные байты в CSV файл"""
|
||
with open(output_file, 'w', encoding='utf-8') as f:
|
||
f.write("адрес;байт;целевой_адрес;исходная_команда\n")
|
||
for addr, byte, target, cmd in csv_lines:
|
||
if cmd and (';' in cmd or '\n' in cmd):
|
||
cmd = '"' + cmd.replace('"', '""') + '"'
|
||
f.write(f"{addr};{byte};{target};{cmd}\n")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
if len(sys.argv) != 4:
|
||
print("Использование: python kvs_pass2.py <вход.аст> <вход.проход1> <выход.csv>")
|
||
sys.exit(1)
|
||
|
||
ast_lines = read_ast(sys.argv[1])
|
||
pass1_data, labels, label_sections, symbols = read_pass1(sys.argv[2])
|
||
|
||
pass2 = Pass2(pass1_data, labels, label_sections, symbols)
|
||
csv_lines = pass2.process_all(ast_lines)
|
||
write_csv(csv_lines, sys.argv[3])
|
||
|
||
print(f"Проход 2: {len(csv_lines)} строк CSV записано в {sys.argv[3]}")
|
||
print(f" .text: {pass2.position['.text']} байт, виртуальный адрес: 0x{pass2.vaddr_text:x}")
|
||
print(f" .data: {pass2.position['.data']} байт, виртуальный адрес: 0x{pass2.vaddr_data:x}") |