474 lines
12 KiB
Python
474 lines
12 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
Кодировщик инструкций фиксированного размера для КВС
|
||
Инструкции, не зависящие от сложной адресации памяти.
|
||
Вынесены из kvs_pass2_encoder.py для упрощения поддержки.
|
||
"""
|
||
|
||
import struct
|
||
from kvs_data import INSTRUCTIONS, REGISTERS, get_reg_info
|
||
|
||
|
||
# ========== MOV регистр-регистр ==========
|
||
|
||
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
|
||
|
||
|
||
# ========== MOV reg8, imm8 ==========
|
||
|
||
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
|
||
|
||
|
||
# ========== CMP/TEST регистр-регистр ==========
|
||
|
||
def encode_cmp_reg_reg(mnemonic, operands):
|
||
"""
|
||
CMP reg, reg - сравнить регистры
|
||
Формат: сравнить <регистр1>, <регистр2>
|
||
Также TEST через проверить.
|
||
"""
|
||
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
|
||
|
||
|
||
# ========== ADD/SUB регистр-регистр ==========
|
||
|
||
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
|
||
|
||
|
||
# ========== MUL/IMUL/DIV/IDIV ==========
|
||
|
||
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
|
||
|
||
|
||
# ========== AND/OR/XOR регистр-регистр ==========
|
||
|
||
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
|
||
|
||
|
||
# ========== NOT/NEG ==========
|
||
|
||
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
|
||
|
||
|
||
# ========== INC/DEC ==========
|
||
|
||
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)
|
||
|
||
|
||
# ========== Стек (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)
|
||
code.append(imm & 0xFF)
|
||
else:
|
||
code.append(0x68)
|
||
code.extend(struct.pack('<i', imm))
|
||
|
||
return code
|
||
|
||
|
||
# ========== Сдвиги и вращения ==========
|
||
|
||
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_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"]
|
||
|
||
|
||
# ========== Инструкции работы с флагами ==========
|
||
|
||
def encode_flag_instruction(mnemonic):
|
||
return INSTRUCTIONS[mnemonic]["opcode"]
|
||
|
||
|
||
# ========== Ввод-вывод ==========
|
||
|
||
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
|
||
|
||
|
||
# ========== Строковые инструкции ==========
|
||
|
||
def encode_string_instruction(mnemonic):
|
||
return INSTRUCTIONS[mnemonic]["opcode"]
|
||
|
||
|
||
# ========== Идентификация процессора ==========
|
||
|
||
def encode_cpuid():
|
||
return INSTRUCTIONS["идентифицировать_процессор"]["opcode"]
|
||
|
||
def encode_rdtsc():
|
||
return INSTRUCTIONS["прочитать_счётчик"]["opcode"]
|
||
|
||
|
||
# ========== XCHG ==========
|
||
|
||
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 |