kvs/kvs_pass2_encoder.py

1128 lines
38 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 -*-
"""
Кодировщик инструкций для КВС
Содержит все функции генерации машинного кода
"""
import struct
import sys
from kvs_data import INSTRUCTIONS, REGISTERS, get_reg_info
def parse_operand(operand, labels, label_sections, symbols, vaddr_text, vaddr_data):
"""
Вычисляет значение операнда.
Поддерживает:
- десятичные числа (123)
- шестнадцатеричные (0x7B)
- метки (имя_метки)
- константы (из .константа)
"""
if operand.isdigit():
return int(operand)
if operand.startswith('0x') or operand.startswith('0X'):
try:
return int(operand, 16)
except ValueError:
pass
if operand in labels:
section = label_sections.get(operand, '.text')
base = vaddr_text if section == '.text' else vaddr_data
return labels[operand] + base
if operand in symbols:
return symbols[operand]
raise ValueError("Неизвестный операнд: " + operand)
def parse_memory_operand(operand_str, labels, label_sections, vaddr_text, vaddr_data):
"""
Разбирает операнд памяти.
Возвращает словарь с информацией или None.
Поддерживает:
- [число] — абсолютный адрес
- [метка] — адрес метки (из .data или .text)
- [регистр] — косвенная адресация (TODO)
"""
if not operand_str.startswith('[') or not operand_str.endswith(']'):
return None
content = operand_str[1:-1].strip()
# Проверяем, является ли содержимое числом
if content.isdigit():
return {
'type': 'absolute',
'address': int(content)
}
elif content.startswith('0x') or content.startswith('0X'):
try:
addr = int(content, 16)
return {
'type': 'absolute',
'address': addr
}
except ValueError:
pass
# Проверяем, является ли содержимое меткой
if content in labels:
section = label_sections.get(content, '.data')
base = vaddr_text if section == '.text' else vaddr_data
addr = labels[content] + base
return {
'type': 'absolute',
'address': addr
}
# TODO: другие типы ([reg], [reg+disp], [reg+reg*scale])
return None
def encode_mov_reg_mem_absolute(reg_info, mem_info, current_pos, vaddr_text):
"""
Кодирует MOV reg, [addr]
Используем RIP-relative адресацию: mov reg, [rip + disp32]
"""
code = bytearray()
reg = reg_info['index']
target_addr = mem_info['address']
# Вычисляем смещение относительно RIP
# Инструкция: REX (1) + opcode (1) + ModRM (1) + disp32 (4) = 7 байт
rip_at_end = vaddr_text + current_pos + 7
offset = target_addr - rip_at_end
# REX префикс (W=1 для 64-бит, R=бит для reg)
rex = 0x48 if reg_info['size'] == 64 else 0x40
if reg >= 8:
rex |= 0x01 # REX.R
code.append(rex)
# Opcode для MOV reg, mem (8B)
code.append(0x8B)
# ModR/M: mod=00 (disp32), reg=reg, r/m=101 (RIP-relative)
modrm = 0x05 | ((reg & 7) << 3)
code.append(modrm)
# disp32 (смещение относительно RIP)
code.extend(struct.pack('<i', offset))
return code
def encode_mov_mem_reg_absolute(reg_info, mem_info, current_pos, vaddr_text):
"""
Кодирует MOV [addr], reg
Используем RIP-relative адресацию: mov [rip + disp32], reg
"""
code = bytearray()
reg = reg_info['index']
target_addr = mem_info['address']
# Вычисляем смещение относительно RIP
rip_at_end = vaddr_text + current_pos + 7
offset = target_addr - rip_at_end
# REX префикс
rex = 0x48 if reg_info['size'] == 64 else 0x40
if reg >= 8:
rex |= 0x01
code.append(rex)
# Opcode для MOV mem, reg (89)
code.append(0x89)
# ModR/M: mod=00, reg=reg, r/m=101
modrm = 0x05 | ((reg & 7) << 3)
code.append(modrm)
# disp32
code.extend(struct.pack('<i', offset))
return code
def encode_mov_reg_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
"""
MOV reg, mem - загрузить из памяти в регистр
Формат: загрузить <регистр>, [<адрес>]
"""
reg_info = get_reg_info(operands[0])
mem_operand = operands[1]
# Пытаемся разобрать операнд памяти
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data)
if mem_info and mem_info['type'] == 'absolute':
return encode_mov_reg_mem_absolute(reg_info, mem_info, current_pos, vaddr_text)
# TODO: другие типы адресации
print(f"Предупреждение: сложная адресация '{mem_operand}' пока не поддерживается", file=sys.stderr)
return b'\x90' * 3
def encode_mov_mem_reg(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
"""
MOV mem, reg - сохранить из регистра в память
Формат: сохранить [<адрес>], <регистр>
"""
mem_operand = operands[0]
reg_info = get_reg_info(operands[1])
# Пытаемся разобрать операнд памяти
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data)
if mem_info and mem_info['type'] == 'absolute':
return encode_mov_mem_reg_absolute(reg_info, mem_info, current_pos, vaddr_text)
# TODO: другие типы адресации
print(f"Предупреждение: сложная адресация '{mem_operand}' пока не поддерживается", file=sys.stderr)
return b'\x90' * 3
def encode_lea_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos):
"""
LEA reg, mem - загрузить эффективный адрес
Формат: загрузить_адрес <регистр>, [<адрес>]
"""
reg_info = get_reg_info(operands[0])
mem_operand = operands[1]
# Пытаемся разобрать операнд памяти
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data)
if mem_info and mem_info['type'] == 'absolute':
target_addr = mem_info['address']
rip_at_end = vaddr_text + current_pos + 7
offset = target_addr - rip_at_end
code = bytearray()
reg = reg_info['index']
rex = 0x48 if reg_info['size'] == 64 else 0x40
if reg >= 8:
rex |= 0x01
if rex != 0x40:
code.append(rex)
code.append(0x8D) # LEA opcode
modrm = 0x05 | ((reg & 7) << 3)
code.append(modrm)
code.extend(struct.pack('<i', offset))
return code
print(f"Предупреждение: LEA с адресацией '{mem_operand}' пока не поддерживается", file=sys.stderr)
return b'\x90' * 3
# ========== 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"]
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_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
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)
code.extend(instr["opcode"])
modrm = 0xC0 | (subop << 3) | 0
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. Инструкции переходов и вызовов ==========
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. Стековые инструкции ==========
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)
code.append(imm & 0xFF)
else:
code.append(0x68)
code.extend(struct.pack('<i', imm))
return code
# ========== 7. Битовые операции ==========
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)
if size == 64:
code.append(0x48)
code.append(0xC1)
subop_map = {
"сдвиг_влево": 4,
"сдвиг_вправо": 5,
"сдвиг_арифметический_вправо": 7,
"вращать_влево": 0,
"вращать_вправо": 1,
}
subop = subop_map.get(mnemonic, 0)
modrm = 0xC0 | (subop << 3) | (reg & 7)
code.append(modrm)
code.append(shift & 0xFF)
return bytes(code)
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)
# ========== 8. Системные и отладочные инструкции ==========
def encode_syscall():
return INSTRUCTIONS["вызов_системы"]["opcode"]
def encode_int(operands):
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():
return INSTRUCTIONS["остановить"]["opcode"]
def encode_int3():
return INSTRUCTIONS["отладка"]["opcode"]
def encode_nop():
return INSTRUCTIONS["нет_операции"]["opcode"]
# ========== 9. Инструкции работы с флагами ==========
def encode_flag_instruction(mnemonic):
return INSTRUCTIONS[mnemonic]["opcode"]
# ========== 10. Ввод-вывод ==========
def encode_in(operands):
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):
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):
return INSTRUCTIONS[mnemonic]["opcode"]
# ========== 12. Инструкции идентификации процессора ==========
def encode_cpuid():
return INSTRUCTIONS["идентифицировать_процессор"]["opcode"]
def encode_rdtsc():
return INSTRUCTIONS["прочитать_счётчик"]["opcode"]
# ========== 13. Инструкции с памятью (регистр-регистр) ==========
def encode_xchg(operands):
"""XCHG reg, reg - обменять регистры"""
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_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
elif mnemonic == "сохранить":
return encode_mov_mem_reg(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
elif mnemonic == "загрузить_адрес":
return encode_lea_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos)
# ----- 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_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}' не реализована")