кодировщик инструкций фиксированного размера
This commit is contained in:
parent
5f7d212dbf
commit
e1259f0b88
71
kvs_data.py
71
kvs_data.py
|
|
@ -238,6 +238,77 @@ INSTRUCTIONS = {
|
|||
}
|
||||
|
||||
|
||||
# Размеры инструкций в байтах (для первого прохода)
|
||||
INSTRUCTION_SIZES = {
|
||||
"переместить_имм": 10,
|
||||
"сравнить_с": 7,
|
||||
"переход": 5,
|
||||
"переход_если_равно": 6,
|
||||
"переход_если_неравно": 6,
|
||||
"переход_если_ноль": 6,
|
||||
"переход_если_не_ноль": 6,
|
||||
"переход_если_меньше": 6,
|
||||
"переход_если_больше": 6,
|
||||
"переход_если_меньше_или_равно": 6,
|
||||
"переход_если_больше_или_равно": 6,
|
||||
"переход_если_перенос": 6,
|
||||
"переход_если_нет_переноса": 6,
|
||||
"вызов_системы": 2,
|
||||
"нет_операции": 1,
|
||||
"короткий_переход": 2,
|
||||
"короткий_переход_если_равно": 2,
|
||||
"короткий_переход_если_неравно": 2,
|
||||
"короткий_переход_если_меньше": 2,
|
||||
"короткий_переход_если_больше": 2,
|
||||
"короткий_переход_если_меньше_или_равно": 2,
|
||||
"короткий_переход_если_больше_или_равно": 2,
|
||||
"короткий_переход_если_перенос": 2,
|
||||
"короткий_переход_если_нет_переноса": 2,
|
||||
"короткий_переход_если_ноль": 2,
|
||||
"короткий_переход_если_не_ноль": 2,
|
||||
"сравнить": 3,
|
||||
"проверить": 3,
|
||||
"вычесть": 3,
|
||||
"прибавить": 3,
|
||||
"увеличить": 3,
|
||||
"уменьшить": 3,
|
||||
"и": 3,
|
||||
"или": 3,
|
||||
"исключающее_или": 3,
|
||||
"инвертировать": 3,
|
||||
"отрицать": 3,
|
||||
"втолкнуть": 2,
|
||||
"вытолкнуть": 2,
|
||||
"втолкнуть_непосредственно": 5,
|
||||
"умножить": 3,
|
||||
"умножить_знаковое": 3,
|
||||
"разделить": 3,
|
||||
"разделить_знаковое": 3,
|
||||
"сдвиг_влево": 4,
|
||||
"сдвиг_вправо": 4,
|
||||
"сдвиг_арифметический_вправо": 4,
|
||||
"вращать_влево": 4,
|
||||
"вращать_вправо": 4,
|
||||
"цикл": 2,
|
||||
"обменять": 4,
|
||||
"прервать": 2,
|
||||
"ввод_байта": 2,
|
||||
"вывод_байта": 2,
|
||||
"установить_перенос": 1,
|
||||
"сбросить_перенос": 1,
|
||||
"установить_направление": 1,
|
||||
"сбросить_направление": 1,
|
||||
"втолкнуть_флаги": 1,
|
||||
"вытолкнуть_флаги": 1,
|
||||
"переместить_байт": 1,
|
||||
"переместить_слово": 1,
|
||||
"сравнить_байты": 1,
|
||||
"сканировать_байт": 1,
|
||||
"идентифицировать_процессор": 2,
|
||||
"прочитать_счётчик": 2,
|
||||
}
|
||||
|
||||
|
||||
# === ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ===
|
||||
|
||||
def get_reg_info(reg_name):
|
||||
|
|
|
|||
42
kvs_lexer.py
42
kvs_lexer.py
|
|
@ -16,25 +16,43 @@
|
|||
"""
|
||||
|
||||
import sys
|
||||
import re
|
||||
|
||||
def error_unterminated_string(line_num):
|
||||
return f"Незакрытая кавычка в строке на строке {line_num}"
|
||||
|
||||
def is_hex_number(s):
|
||||
"""Проверяет, является ли строка шестнадцатеричным числом (0x... или 0X...)"""
|
||||
return re.match(r'^0[xX][0-9a-fA-F]+$', s) is not None
|
||||
if len(s) < 3:
|
||||
return False
|
||||
if not (s[0] == '0' and (s[1] == 'x' or s[1] == 'X')):
|
||||
return False
|
||||
for ch in s[2:]:
|
||||
if not (('0' <= ch <= '9') or ('a' <= ch <= 'f') or ('A' <= ch <= 'F')):
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_dec_number(s):
|
||||
"""Проверяет, является ли строка десятичным числом (возможно с минусом)"""
|
||||
if s.startswith('-'):
|
||||
s = s[1:]
|
||||
return s.isdigit()
|
||||
if not s:
|
||||
return False
|
||||
start = 0
|
||||
if s[0] == '-':
|
||||
if len(s) == 1:
|
||||
return False
|
||||
start = 1
|
||||
for ch in s[start:]:
|
||||
if ch < '0' or ch > '9':
|
||||
return False
|
||||
return True
|
||||
|
||||
def tokenize_line(line, line_num):
|
||||
"""Разбирает строку в токены"""
|
||||
# Удаляем комментарии
|
||||
semi = line.find(';')
|
||||
semi = -1
|
||||
for idx in range(len(line)):
|
||||
if line[idx] == ';':
|
||||
semi = idx
|
||||
break
|
||||
if semi != -1:
|
||||
line = line[:semi]
|
||||
line = line.rstrip()
|
||||
|
|
@ -49,7 +67,7 @@ def tokenize_line(line, line_num):
|
|||
ch = line[i]
|
||||
|
||||
# Пропускаем пробелы
|
||||
if ch.isspace():
|
||||
if ch == ' ' or ch == '\t':
|
||||
i += 1
|
||||
continue
|
||||
|
||||
|
|
@ -81,7 +99,7 @@ def tokenize_line(line, line_num):
|
|||
i += 1
|
||||
continue
|
||||
|
||||
# НОВЫЕ ТОКЕНЫ ДЛЯ СЛОЖНОЙ АДРЕСАЦИИ
|
||||
# ТОКЕНЫ ДЛЯ СЛОЖНОЙ АДРЕСАЦИИ
|
||||
if ch == '[':
|
||||
tokens.append(('LBRACKET', '['))
|
||||
i += 1
|
||||
|
|
@ -98,12 +116,6 @@ def tokenize_line(line, line_num):
|
|||
continue
|
||||
|
||||
if ch == '-':
|
||||
# Проверяем, не является ли это началом отрицательного числа
|
||||
# Смотрим следующий символ
|
||||
if i + 1 < n and (line[i + 1].isdigit() or line[i + 1] == '0'):
|
||||
# Возможно отрицательное число, дадим разобраться дальше
|
||||
# Но для простоты сохраняем как MINUS, а число будет отдельным токеном
|
||||
pass
|
||||
tokens.append(('MINUS', '-'))
|
||||
i += 1
|
||||
continue
|
||||
|
|
@ -115,7 +127,7 @@ def tokenize_line(line, line_num):
|
|||
|
||||
# Слова, числа, метки
|
||||
j = i
|
||||
while j < n and not (line[j].isspace() or line[j] in ',:;[]+*-'):
|
||||
while j < n and not (line[j] in ' \t,;:[]+*-'):
|
||||
j += 1
|
||||
word = line[i:j]
|
||||
|
||||
|
|
|
|||
184
kvs_pass1.py
184
kvs_pass1.py
|
|
@ -7,9 +7,8 @@
|
|||
"""
|
||||
|
||||
import sys
|
||||
import re
|
||||
sys.path.insert(0, '.')
|
||||
from kvs_data import PAGE_SIZE, text_vaddr_base, data_vaddr_base, align_up, INSTRUCTIONS
|
||||
from kvs_data import PAGE_SIZE, text_vaddr_base, align_up, INSTRUCTIONS, INSTRUCTION_SIZES
|
||||
|
||||
def unescape_string(s):
|
||||
"""Преобразует escape-последовательности в реальные символы"""
|
||||
|
|
@ -39,6 +38,56 @@ def read_ast(input_file):
|
|||
ast_lines.append(line.strip())
|
||||
return ast_lines
|
||||
|
||||
def is_hex_number(s):
|
||||
"""Проверяет, является ли строка шестнадцатеричным числом"""
|
||||
if len(s) < 3:
|
||||
return False
|
||||
if not (s[0] == '0' and (s[1] == 'x' or s[1] == 'X')):
|
||||
return False
|
||||
for ch in s[2:]:
|
||||
if not (('0' <= ch <= '9') or ('a' <= ch <= 'f') or ('A' <= ch <= 'F')):
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_dec_number(s):
|
||||
"""Проверяет, является ли строка десятичным числом (возможно с минусом)"""
|
||||
if not s:
|
||||
return False
|
||||
start = 0
|
||||
if s[0] == '-':
|
||||
if len(s) == 1:
|
||||
return False
|
||||
start = 1
|
||||
for ch in s[start:]:
|
||||
if ch < '0' or ch > '9':
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_register(s):
|
||||
"""Проверяет, является ли строка именем регистра"""
|
||||
return s in ['раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15']
|
||||
|
||||
def split_by_operators(content):
|
||||
"""
|
||||
Разбивает строку по операторам + и - с сохранением операторов.
|
||||
Аналог re.split(r'([+\-])', content)
|
||||
Пример: "раикс + рбикс*4 - 8" -> ["раикс ", "+", " рбикс*4 ", "-", " 8"]
|
||||
"""
|
||||
parts = []
|
||||
current = ''
|
||||
for ch in content:
|
||||
if ch == '+' or ch == '-':
|
||||
if current:
|
||||
parts.append(current)
|
||||
parts.append(ch)
|
||||
current = ''
|
||||
else:
|
||||
current += ch
|
||||
if current:
|
||||
parts.append(current)
|
||||
return parts
|
||||
|
||||
def parse_memory_operand(operand_str):
|
||||
"""
|
||||
Анализирует операнд памяти вида [reg + reg*scale + disp]
|
||||
|
|
@ -71,9 +120,9 @@ def parse_memory_operand(operand_str):
|
|||
}
|
||||
|
||||
# Проверяем, не является ли содержимое просто числом (абсолютный адрес)
|
||||
if content.isdigit() or (content.startswith('0x') and len(content) > 2 and content[2:].replace('0','').replace('1','').replace('2','').replace('3','').replace('4','').replace('5','').replace('6','').replace('7','').replace('8','').replace('9','').replace('a','').replace('b','').replace('c','').replace('d','').replace('e','').replace('f','').replace('A','').replace('B','').replace('C','').replace('D','').replace('E','').replace('F','') == ''):
|
||||
if is_dec_number(content) or is_hex_number(content):
|
||||
result['has_disp'] = True
|
||||
if content.startswith('0x'):
|
||||
if content.startswith('0x') or content.startswith('0X'):
|
||||
result['disp_value'] = int(content, 16)
|
||||
else:
|
||||
result['disp_value'] = int(content)
|
||||
|
|
@ -81,43 +130,41 @@ def parse_memory_operand(operand_str):
|
|||
return result
|
||||
|
||||
# Простой регистр без смещения
|
||||
if content in ['раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15']:
|
||||
if is_register(content):
|
||||
result['has_base'] = True
|
||||
result['base_reg'] = content
|
||||
return result
|
||||
|
||||
# Разбираем выражение: регистр [+- регистр[*масштаб] [+- смещение]]
|
||||
parts = re.split(r'([+\-])', content)
|
||||
parts = split_by_operators(content)
|
||||
|
||||
for part in parts:
|
||||
part = part.strip()
|
||||
if not part or part in '+-':
|
||||
if not part or part == '+' or part == '-':
|
||||
continue
|
||||
|
||||
if part in ['раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15']:
|
||||
if is_register(part):
|
||||
if not result['has_base']:
|
||||
result['has_base'] = True
|
||||
result['base_reg'] = part
|
||||
elif not result['has_index']:
|
||||
result['has_index'] = True
|
||||
result['index_reg'] = part
|
||||
elif part.isdigit() or (part.startswith('0x') and len(part) > 2):
|
||||
elif is_dec_number(part) or is_hex_number(part):
|
||||
result['has_disp'] = True
|
||||
if part.startswith('0x'):
|
||||
if part.startswith('0x') or part.startswith('0X'):
|
||||
result['disp_value'] = int(part, 16)
|
||||
else:
|
||||
result['disp_value'] = int(part)
|
||||
elif '*' in part:
|
||||
reg_part, scale_part = part.split('*')
|
||||
reg_part = reg_part.strip()
|
||||
scale_part = scale_part.strip()
|
||||
if reg_part in ['раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
||||
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15']:
|
||||
result['has_index'] = True
|
||||
result['index_reg'] = reg_part
|
||||
result['scale'] = int(scale_part)
|
||||
star_pos = part.find('*')
|
||||
if star_pos != -1:
|
||||
reg_part = part[:star_pos].strip()
|
||||
scale_part = part[star_pos + 1:].strip()
|
||||
if is_register(reg_part):
|
||||
result['has_index'] = True
|
||||
result['index_reg'] = reg_part
|
||||
result['scale'] = int(scale_part)
|
||||
|
||||
if result['has_disp']:
|
||||
if -128 <= result['disp_value'] <= 127:
|
||||
|
|
@ -179,16 +226,20 @@ class Pass1:
|
|||
elif directive == '.константа':
|
||||
name = parts[2]
|
||||
value_str = parts[3]
|
||||
if value_str.isdigit():
|
||||
if is_dec_number(value_str):
|
||||
self.symbols[name] = int(value_str)
|
||||
elif value_str.startswith('0x'):
|
||||
elif is_hex_number(value_str):
|
||||
self.symbols[name] = int(value_str, 16)
|
||||
else:
|
||||
self.symbols[name] = 0
|
||||
elif directive == '.байт':
|
||||
sec = parts[2]
|
||||
if len(parts) > 3 and parts[3]:
|
||||
num_bytes = len(parts[3].split(','))
|
||||
# Считаем количество значений, разделённых запятыми
|
||||
num_bytes = 1
|
||||
for ch in parts[3]:
|
||||
if ch == ',':
|
||||
num_bytes += 1
|
||||
self.position[sec] += num_bytes
|
||||
|
||||
# Директивы резервирования в .бнд
|
||||
|
|
@ -218,7 +269,18 @@ class Pass1:
|
|||
mnemonic = parts[1]
|
||||
sec = parts[2]
|
||||
operands_str = parts[3] if len(parts) > 3 else ""
|
||||
operands = operands_str.split(',') if operands_str else []
|
||||
operands = []
|
||||
if operands_str:
|
||||
# Разбиваем по запятым
|
||||
current = ''
|
||||
for ch in operands_str:
|
||||
if ch == ',':
|
||||
operands.append(current)
|
||||
current = ''
|
||||
else:
|
||||
current += ch
|
||||
if current:
|
||||
operands.append(current)
|
||||
size = self.estimate_size(mnemonic, operands)
|
||||
self.position[sec] += size
|
||||
|
||||
|
|
@ -230,83 +292,15 @@ class Pass1:
|
|||
# RIP-relative: REX (1) + opcode (1) + ModR/M (1) + disp32 (4) = 7
|
||||
return 7
|
||||
|
||||
# Инструкции без операндов
|
||||
# Инструкции без операндов — размер из INSTRUCTIONS
|
||||
if mnemonic in ("вызов_системы", "нет_операции", "вернуться", "остановить", "отладка"):
|
||||
instr = INSTRUCTIONS.get(mnemonic)
|
||||
if instr and "opcode" in instr:
|
||||
return len(instr["opcode"])
|
||||
return 2
|
||||
|
||||
# Таблица фиксированных размеров
|
||||
size_map = {
|
||||
"переместить_имм": 10,
|
||||
"сравнить_с": 7,
|
||||
"переход": 5,
|
||||
"переход_если_равно": 6,
|
||||
"переход_если_неравно": 6,
|
||||
"переход_если_ноль": 6,
|
||||
"переход_если_не_ноль": 6,
|
||||
"переход_если_меньше": 6,
|
||||
"переход_если_больше": 6,
|
||||
"переход_если_меньше_или_равно": 6,
|
||||
"переход_если_больше_или_равно": 6,
|
||||
"переход_если_перенос": 6,
|
||||
"переход_если_нет_переноса": 6,
|
||||
"вызов_системы": 2,
|
||||
"нет_операции": 1,
|
||||
"короткий_переход": 2,
|
||||
"короткий_переход_если_равно": 2,
|
||||
"короткий_переход_если_неравно": 2,
|
||||
"короткий_переход_если_меньше": 2,
|
||||
"короткий_переход_если_больше": 2,
|
||||
"короткий_переход_если_меньше_или_равно": 2,
|
||||
"короткий_переход_если_больше_или_равно": 2,
|
||||
"короткий_переход_если_перенос": 2,
|
||||
"короткий_переход_если_нет_переноса": 2,
|
||||
"короткий_переход_если_ноль": 2,
|
||||
"короткий_переход_если_не_ноль": 2,
|
||||
"сравнить": 3,
|
||||
"проверить": 3,
|
||||
"вычесть": 3,
|
||||
"прибавить": 3,
|
||||
"увеличить": 3,
|
||||
"уменьшить": 3,
|
||||
"и": 3,
|
||||
"или": 3,
|
||||
"исключающее_или": 3,
|
||||
"инвертировать": 3,
|
||||
"отрицать": 3,
|
||||
"втолкнуть": 2,
|
||||
"вытолкнуть": 2,
|
||||
"втолкнуть_непосредственно": 5,
|
||||
"умножить": 3,
|
||||
"умножить_знаковое": 3,
|
||||
"разделить": 3,
|
||||
"разделить_знаковое": 3,
|
||||
"сдвиг_влево": 4,
|
||||
"сдвиг_вправо": 4,
|
||||
"сдвиг_арифметический_вправо": 4,
|
||||
"вращать_влево": 4,
|
||||
"вращать_вправо": 4,
|
||||
"цикл": 2,
|
||||
"обменять": 4,
|
||||
"прервать": 2,
|
||||
"ввод_байта": 2,
|
||||
"вывод_байта": 2,
|
||||
"установить_перенос": 1,
|
||||
"сбросить_перенос": 1,
|
||||
"установить_направление": 1,
|
||||
"сбросить_направление": 1,
|
||||
"втолкнуть_флаги": 1,
|
||||
"вытолкнуть_флаги": 1,
|
||||
"переместить_байт": 1,
|
||||
"переместить_слово": 1,
|
||||
"сравнить_байты": 1,
|
||||
"сканировать_байт": 1,
|
||||
"идентифицировать_процессор": 2,
|
||||
"прочитать_счётчик": 2,
|
||||
}
|
||||
return size_map.get(mnemonic, 3)
|
||||
# Фиксированные размеры из общей таблицы
|
||||
return INSTRUCTION_SIZES.get(mnemonic, 3)
|
||||
|
||||
def calculate_layout(self):
|
||||
text_size = self.position[".text"]
|
||||
|
|
|
|||
37
kvs_pass2.py
37
kvs_pass2.py
|
|
@ -91,11 +91,8 @@ class Pass2:
|
|||
self.symbols = symbols
|
||||
self.vaddr_text = pass1_data["vaddr_text"]
|
||||
text_size = pass1_data["text_size"]
|
||||
data_size = pass1_data["data_size"]
|
||||
self.vaddr_data = align_up(self.vaddr_text + text_size, PAGE_SIZE)
|
||||
self.vaddr_bnd = pass1_data.get("vaddr_bnd", align_up(self.vaddr_data + data_size, PAGE_SIZE))
|
||||
self.bnd_size = pass1_data.get("bnd_size", 0)
|
||||
self.position = {".text": 0, ".data": 0, ".бнд": 0}
|
||||
self.position = {".text": 0, ".data": 0}
|
||||
self.current_section = ".text"
|
||||
self.csv_lines = []
|
||||
self.data_bytes = {".text": bytearray(), ".data": bytearray()}
|
||||
|
|
@ -122,14 +119,7 @@ class Pass2:
|
|||
op_str = operands[1]
|
||||
if op_str in self.labels:
|
||||
sec = self.label_sections[op_str]
|
||||
if sec == ".text":
|
||||
addr = self.labels[op_str] + self.vaddr_text
|
||||
elif sec == ".data":
|
||||
addr = self.labels[op_str] + self.vaddr_data
|
||||
elif sec == ".бнд":
|
||||
addr = self.labels[op_str] + self.vaddr_bnd
|
||||
else:
|
||||
addr = self.labels[op_str] + self.vaddr_text
|
||||
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])
|
||||
|
|
@ -149,8 +139,6 @@ class Pass2:
|
|||
self.current_section = ".text"
|
||||
elif directive == '.данные':
|
||||
self.current_section = ".data"
|
||||
elif directive == '.бнд':
|
||||
self.current_section = ".бнд"
|
||||
elif directive in ('.строка_нуль', '.строка'):
|
||||
s = parts[3] if len(parts) > 3 else ""
|
||||
real_s = unescape_string(s)
|
||||
|
|
@ -192,23 +180,6 @@ class Pass2:
|
|||
self.data_bytes[".data"].append(val & 0xFF)
|
||||
|
||||
self.position[".data"] += len(byte_values)
|
||||
|
||||
# Директивы резервирования в .бнд — не генерируют байты
|
||||
elif directive == '.резб':
|
||||
count = int(parts[3])
|
||||
self.position['.бнд'] += count * 1
|
||||
|
||||
elif directive == '.резс':
|
||||
count = int(parts[3])
|
||||
self.position['.бнд'] += count * 2
|
||||
|
||||
elif directive == '.рездс':
|
||||
count = int(parts[3])
|
||||
self.position['.бнд'] += count * 4
|
||||
|
||||
elif directive == '.резкс':
|
||||
count = int(parts[3])
|
||||
self.position['.бнд'] += count * 8
|
||||
|
||||
elif line_type == "LABEL":
|
||||
label_name = parts[1]
|
||||
|
|
@ -278,6 +249,4 @@ if __name__ == "__main__":
|
|||
|
||||
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}")
|
||||
if pass2.bnd_size > 0:
|
||||
print(f" .бнд: {pass2.bnd_size} байт, виртуальный адрес: 0x{pass2.vaddr_bnd:x}")
|
||||
print(f" .data: {pass2.position['.data']} байт, виртуальный адрес: 0x{pass2.vaddr_data:x}")
|
||||
|
|
@ -3,14 +3,44 @@
|
|||
|
||||
"""
|
||||
Кодировщик инструкций для КВС
|
||||
Содержит все функции генерации машинного кода
|
||||
Содержит все функции генерации машинного кода.
|
||||
Фиксированные инструкции вынесены в kvs_pass2_encoder_fixsize.py.
|
||||
Здесь остаются: parse_operand, parse_memory_operand, инструкции с адресацией, диспетчер.
|
||||
"""
|
||||
|
||||
import struct
|
||||
import sys
|
||||
from kvs_data import INSTRUCTIONS, REGISTERS, get_reg_info
|
||||
from kvs_pass2_encoder_fixsize import (
|
||||
encode_mov_reg_reg,
|
||||
encode_mov_reg8_imm8,
|
||||
encode_cmp_reg_reg,
|
||||
encode_add_sub_reg_reg,
|
||||
encode_muldiv,
|
||||
encode_and_or_xor_reg_reg,
|
||||
encode_not_neg,
|
||||
encode_incdec,
|
||||
encode_push_reg,
|
||||
encode_pop_reg,
|
||||
encode_push_imm,
|
||||
encode_shift_rotate,
|
||||
encode_syscall,
|
||||
encode_int,
|
||||
encode_hlt,
|
||||
encode_int3,
|
||||
encode_nop,
|
||||
encode_flag_instruction,
|
||||
encode_in,
|
||||
encode_out,
|
||||
encode_string_instruction,
|
||||
encode_cpuid,
|
||||
encode_rdtsc,
|
||||
encode_xchg,
|
||||
)
|
||||
|
||||
|
||||
# ========== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ==========
|
||||
|
||||
def parse_operand(operand, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd=None):
|
||||
"""
|
||||
Вычисляет значение операнда.
|
||||
|
|
@ -96,6 +126,8 @@ def parse_memory_operand(operand_str, labels, label_sections, vaddr_text, vaddr_
|
|||
return None
|
||||
|
||||
|
||||
# ========== MOV С ПАМЯТЬЮ ==========
|
||||
|
||||
def encode_mov_reg_mem_absolute(reg_info, mem_info, current_pos, vaddr_text):
|
||||
"""
|
||||
Кодирует MOV reg, [addr]
|
||||
|
|
@ -169,12 +201,10 @@ def encode_mov_reg_mem(operands, labels, label_sections, symbols, vaddr_text, va
|
|||
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, vaddr_bnd)
|
||||
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
|
||||
|
||||
|
|
@ -187,12 +217,10 @@ def encode_mov_mem_reg(operands, labels, label_sections, symbols, vaddr_text, va
|
|||
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, vaddr_bnd)
|
||||
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
|
||||
|
||||
|
|
@ -205,7 +233,6 @@ def encode_lea_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_
|
|||
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, vaddr_bnd)
|
||||
if mem_info and mem_info['type'] == 'absolute':
|
||||
target_addr = mem_info['address']
|
||||
|
|
@ -231,7 +258,7 @@ def encode_lea_mem(operands, labels, label_sections, symbols, vaddr_text, vaddr_
|
|||
return b'\x90' * 3
|
||||
|
||||
|
||||
# ========== 1. Инструкции перемещения данных (MOV, LEA, MOVZX, MOVSX) ==========
|
||||
# ========== MOV reg, imm (зависит от parse_operand) ==========
|
||||
|
||||
def encode_mov_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd=None):
|
||||
"""
|
||||
|
|
@ -291,65 +318,7 @@ def encode_mov_reg_imm(operands, labels, label_sections, symbols, vaddr_text, va
|
|||
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
|
||||
|
||||
# ========== MOVZX/MOVSX (зависят от parse_operand) ==========
|
||||
|
||||
def encode_movzx(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd=None):
|
||||
"""
|
||||
|
|
@ -395,7 +364,7 @@ def encode_movsx(operands, labels, label_sections, symbols, vaddr_text, vaddr_da
|
|||
return code
|
||||
|
||||
|
||||
# ========== 2. Инструкции сравнения (CMP, TEST) ==========
|
||||
# ========== CMP reg, imm (зависит от parse_operand) ==========
|
||||
|
||||
def encode_cmp_reg_imm(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd=None):
|
||||
"""
|
||||
|
|
@ -472,42 +441,7 @@ def encode_cmp_reg_imm(operands, labels, label_sections, symbols, vaddr_text, va
|
|||
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) ==========
|
||||
# ========== ADD/SUB reg, imm (зависит от parse_operand) ==========
|
||||
|
||||
def encode_add_sub_reg_imm(mnemonic, operands, labels, label_sections, symbols, vaddr_text, vaddr_data, vaddr_bnd=None):
|
||||
"""
|
||||
|
|
@ -573,119 +507,7 @@ def encode_add_sub_reg_imm(mnemonic, operands, labels, label_sections, symbols,
|
|||
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. Инструкции переходов и вызовов ==========
|
||||
# ========== ПЕРЕХОДЫ И ВЫЗОВЫ (зависят от parse_operand) ==========
|
||||
|
||||
def encode_jmp_rel32(operands, labels, label_sections, symbols, vaddr_text, vaddr_data, current_pos, vaddr_bnd=None):
|
||||
"""
|
||||
|
|
@ -775,247 +597,6 @@ def encode_loop(operands, labels, label_sections, symbols, vaddr_text, vaddr_dat
|
|||
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, vaddr_bnd=None):
|
||||
|
|
|
|||
474
kvs_pass2_encoder_fixsize.py
Normal file
474
kvs_pass2_encoder_fixsize.py
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
#!/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
|
||||
Loading…
Reference in a new issue