кодировщик инструкций фиксированного размера
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):
|
def get_reg_info(reg_name):
|
||||||
|
|
|
||||||
42
kvs_lexer.py
42
kvs_lexer.py
|
|
@ -16,25 +16,43 @@
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import re
|
|
||||||
|
|
||||||
def error_unterminated_string(line_num):
|
def error_unterminated_string(line_num):
|
||||||
return f"Незакрытая кавычка в строке на строке {line_num}"
|
return f"Незакрытая кавычка в строке на строке {line_num}"
|
||||||
|
|
||||||
def is_hex_number(s):
|
def is_hex_number(s):
|
||||||
"""Проверяет, является ли строка шестнадцатеричным числом (0x... или 0X...)"""
|
"""Проверяет, является ли строка шестнадцатеричным числом (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):
|
def is_dec_number(s):
|
||||||
"""Проверяет, является ли строка десятичным числом (возможно с минусом)"""
|
"""Проверяет, является ли строка десятичным числом (возможно с минусом)"""
|
||||||
if s.startswith('-'):
|
if not s:
|
||||||
s = s[1:]
|
return False
|
||||||
return s.isdigit()
|
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):
|
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:
|
if semi != -1:
|
||||||
line = line[:semi]
|
line = line[:semi]
|
||||||
line = line.rstrip()
|
line = line.rstrip()
|
||||||
|
|
@ -49,7 +67,7 @@ def tokenize_line(line, line_num):
|
||||||
ch = line[i]
|
ch = line[i]
|
||||||
|
|
||||||
# Пропускаем пробелы
|
# Пропускаем пробелы
|
||||||
if ch.isspace():
|
if ch == ' ' or ch == '\t':
|
||||||
i += 1
|
i += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -81,7 +99,7 @@ def tokenize_line(line, line_num):
|
||||||
i += 1
|
i += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# НОВЫЕ ТОКЕНЫ ДЛЯ СЛОЖНОЙ АДРЕСАЦИИ
|
# ТОКЕНЫ ДЛЯ СЛОЖНОЙ АДРЕСАЦИИ
|
||||||
if ch == '[':
|
if ch == '[':
|
||||||
tokens.append(('LBRACKET', '['))
|
tokens.append(('LBRACKET', '['))
|
||||||
i += 1
|
i += 1
|
||||||
|
|
@ -98,12 +116,6 @@ def tokenize_line(line, line_num):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if ch == '-':
|
if ch == '-':
|
||||||
# Проверяем, не является ли это началом отрицательного числа
|
|
||||||
# Смотрим следующий символ
|
|
||||||
if i + 1 < n and (line[i + 1].isdigit() or line[i + 1] == '0'):
|
|
||||||
# Возможно отрицательное число, дадим разобраться дальше
|
|
||||||
# Но для простоты сохраняем как MINUS, а число будет отдельным токеном
|
|
||||||
pass
|
|
||||||
tokens.append(('MINUS', '-'))
|
tokens.append(('MINUS', '-'))
|
||||||
i += 1
|
i += 1
|
||||||
continue
|
continue
|
||||||
|
|
@ -115,7 +127,7 @@ def tokenize_line(line, line_num):
|
||||||
|
|
||||||
# Слова, числа, метки
|
# Слова, числа, метки
|
||||||
j = i
|
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
|
j += 1
|
||||||
word = line[i:j]
|
word = line[i:j]
|
||||||
|
|
||||||
|
|
|
||||||
184
kvs_pass1.py
184
kvs_pass1.py
|
|
@ -7,9 +7,8 @@
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import re
|
|
||||||
sys.path.insert(0, '.')
|
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):
|
def unescape_string(s):
|
||||||
"""Преобразует escape-последовательности в реальные символы"""
|
"""Преобразует escape-последовательности в реальные символы"""
|
||||||
|
|
@ -39,6 +38,56 @@ def read_ast(input_file):
|
||||||
ast_lines.append(line.strip())
|
ast_lines.append(line.strip())
|
||||||
return ast_lines
|
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):
|
def parse_memory_operand(operand_str):
|
||||||
"""
|
"""
|
||||||
Анализирует операнд памяти вида [reg + reg*scale + disp]
|
Анализирует операнд памяти вида [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
|
result['has_disp'] = True
|
||||||
if content.startswith('0x'):
|
if content.startswith('0x') or content.startswith('0X'):
|
||||||
result['disp_value'] = int(content, 16)
|
result['disp_value'] = int(content, 16)
|
||||||
else:
|
else:
|
||||||
result['disp_value'] = int(content)
|
result['disp_value'] = int(content)
|
||||||
|
|
@ -81,43 +130,41 @@ def parse_memory_operand(operand_str):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# Простой регистр без смещения
|
# Простой регистр без смещения
|
||||||
if content in ['раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
if is_register(content):
|
||||||
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15']:
|
|
||||||
result['has_base'] = True
|
result['has_base'] = True
|
||||||
result['base_reg'] = content
|
result['base_reg'] = content
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# Разбираем выражение: регистр [+- регистр[*масштаб] [+- смещение]]
|
# Разбираем выражение: регистр [+- регистр[*масштаб] [+- смещение]]
|
||||||
parts = re.split(r'([+\-])', content)
|
parts = split_by_operators(content)
|
||||||
|
|
||||||
for part in parts:
|
for part in parts:
|
||||||
part = part.strip()
|
part = part.strip()
|
||||||
if not part or part in '+-':
|
if not part or part == '+' or part == '-':
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if part in ['раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
if is_register(part):
|
||||||
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15']:
|
|
||||||
if not result['has_base']:
|
if not result['has_base']:
|
||||||
result['has_base'] = True
|
result['has_base'] = True
|
||||||
result['base_reg'] = part
|
result['base_reg'] = part
|
||||||
elif not result['has_index']:
|
elif not result['has_index']:
|
||||||
result['has_index'] = True
|
result['has_index'] = True
|
||||||
result['index_reg'] = part
|
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
|
result['has_disp'] = True
|
||||||
if part.startswith('0x'):
|
if part.startswith('0x') or part.startswith('0X'):
|
||||||
result['disp_value'] = int(part, 16)
|
result['disp_value'] = int(part, 16)
|
||||||
else:
|
else:
|
||||||
result['disp_value'] = int(part)
|
result['disp_value'] = int(part)
|
||||||
elif '*' in part:
|
elif '*' in part:
|
||||||
reg_part, scale_part = part.split('*')
|
star_pos = part.find('*')
|
||||||
reg_part = reg_part.strip()
|
if star_pos != -1:
|
||||||
scale_part = scale_part.strip()
|
reg_part = part[:star_pos].strip()
|
||||||
if reg_part in ['раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай',
|
scale_part = part[star_pos + 1:].strip()
|
||||||
'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15']:
|
if is_register(reg_part):
|
||||||
result['has_index'] = True
|
result['has_index'] = True
|
||||||
result['index_reg'] = reg_part
|
result['index_reg'] = reg_part
|
||||||
result['scale'] = int(scale_part)
|
result['scale'] = int(scale_part)
|
||||||
|
|
||||||
if result['has_disp']:
|
if result['has_disp']:
|
||||||
if -128 <= result['disp_value'] <= 127:
|
if -128 <= result['disp_value'] <= 127:
|
||||||
|
|
@ -179,16 +226,20 @@ class Pass1:
|
||||||
elif directive == '.константа':
|
elif directive == '.константа':
|
||||||
name = parts[2]
|
name = parts[2]
|
||||||
value_str = parts[3]
|
value_str = parts[3]
|
||||||
if value_str.isdigit():
|
if is_dec_number(value_str):
|
||||||
self.symbols[name] = int(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)
|
self.symbols[name] = int(value_str, 16)
|
||||||
else:
|
else:
|
||||||
self.symbols[name] = 0
|
self.symbols[name] = 0
|
||||||
elif directive == '.байт':
|
elif directive == '.байт':
|
||||||
sec = parts[2]
|
sec = parts[2]
|
||||||
if len(parts) > 3 and parts[3]:
|
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
|
self.position[sec] += num_bytes
|
||||||
|
|
||||||
# Директивы резервирования в .бнд
|
# Директивы резервирования в .бнд
|
||||||
|
|
@ -218,7 +269,18 @@ class Pass1:
|
||||||
mnemonic = parts[1]
|
mnemonic = parts[1]
|
||||||
sec = parts[2]
|
sec = parts[2]
|
||||||
operands_str = parts[3] if len(parts) > 3 else ""
|
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)
|
size = self.estimate_size(mnemonic, operands)
|
||||||
self.position[sec] += size
|
self.position[sec] += size
|
||||||
|
|
||||||
|
|
@ -230,83 +292,15 @@ class Pass1:
|
||||||
# RIP-relative: REX (1) + opcode (1) + ModR/M (1) + disp32 (4) = 7
|
# RIP-relative: REX (1) + opcode (1) + ModR/M (1) + disp32 (4) = 7
|
||||||
return 7
|
return 7
|
||||||
|
|
||||||
# Инструкции без операндов
|
# Инструкции без операндов — размер из INSTRUCTIONS
|
||||||
if mnemonic in ("вызов_системы", "нет_операции", "вернуться", "остановить", "отладка"):
|
if mnemonic in ("вызов_системы", "нет_операции", "вернуться", "остановить", "отладка"):
|
||||||
instr = INSTRUCTIONS.get(mnemonic)
|
instr = INSTRUCTIONS.get(mnemonic)
|
||||||
if instr and "opcode" in instr:
|
if instr and "opcode" in instr:
|
||||||
return len(instr["opcode"])
|
return len(instr["opcode"])
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
# Таблица фиксированных размеров
|
# Фиксированные размеры из общей таблицы
|
||||||
size_map = {
|
return INSTRUCTION_SIZES.get(mnemonic, 3)
|
||||||
"переместить_имм": 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)
|
|
||||||
|
|
||||||
def calculate_layout(self):
|
def calculate_layout(self):
|
||||||
text_size = self.position[".text"]
|
text_size = self.position[".text"]
|
||||||
|
|
|
||||||
37
kvs_pass2.py
37
kvs_pass2.py
|
|
@ -91,11 +91,8 @@ class Pass2:
|
||||||
self.symbols = symbols
|
self.symbols = symbols
|
||||||
self.vaddr_text = pass1_data["vaddr_text"]
|
self.vaddr_text = pass1_data["vaddr_text"]
|
||||||
text_size = pass1_data["text_size"]
|
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_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.position = {".text": 0, ".data": 0}
|
||||||
self.bnd_size = pass1_data.get("bnd_size", 0)
|
|
||||||
self.position = {".text": 0, ".data": 0, ".бнд": 0}
|
|
||||||
self.current_section = ".text"
|
self.current_section = ".text"
|
||||||
self.csv_lines = []
|
self.csv_lines = []
|
||||||
self.data_bytes = {".text": bytearray(), ".data": bytearray()}
|
self.data_bytes = {".text": bytearray(), ".data": bytearray()}
|
||||||
|
|
@ -122,14 +119,7 @@ class Pass2:
|
||||||
op_str = operands[1]
|
op_str = operands[1]
|
||||||
if op_str in self.labels:
|
if op_str in self.labels:
|
||||||
sec = self.label_sections[op_str]
|
sec = self.label_sections[op_str]
|
||||||
if sec == ".text":
|
addr = self.labels[op_str] + (self.vaddr_text if sec == ".text" else self.vaddr_data)
|
||||||
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
|
|
||||||
return hex(addr)
|
return hex(addr)
|
||||||
elif op_str in self.symbols:
|
elif op_str in self.symbols:
|
||||||
return hex(self.symbols[op_str])
|
return hex(self.symbols[op_str])
|
||||||
|
|
@ -149,8 +139,6 @@ class Pass2:
|
||||||
self.current_section = ".text"
|
self.current_section = ".text"
|
||||||
elif directive == '.данные':
|
elif directive == '.данные':
|
||||||
self.current_section = ".data"
|
self.current_section = ".data"
|
||||||
elif directive == '.бнд':
|
|
||||||
self.current_section = ".бнд"
|
|
||||||
elif directive in ('.строка_нуль', '.строка'):
|
elif directive in ('.строка_нуль', '.строка'):
|
||||||
s = parts[3] if len(parts) > 3 else ""
|
s = parts[3] if len(parts) > 3 else ""
|
||||||
real_s = unescape_string(s)
|
real_s = unescape_string(s)
|
||||||
|
|
@ -192,23 +180,6 @@ class Pass2:
|
||||||
self.data_bytes[".data"].append(val & 0xFF)
|
self.data_bytes[".data"].append(val & 0xFF)
|
||||||
|
|
||||||
self.position[".data"] += len(byte_values)
|
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":
|
elif line_type == "LABEL":
|
||||||
label_name = parts[1]
|
label_name = parts[1]
|
||||||
|
|
@ -278,6 +249,4 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
print(f"Проход 2: {len(csv_lines)} строк CSV записано в {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" .text: {pass2.position['.text']} байт, виртуальный адрес: 0x{pass2.vaddr_text:x}")
|
||||||
print(f" .data: {pass2.position['.data']} байт, виртуальный адрес: 0x{pass2.vaddr_data: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}")
|
|
||||||
|
|
@ -3,14 +3,44 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Кодировщик инструкций для КВС
|
Кодировщик инструкций для КВС
|
||||||
Содержит все функции генерации машинного кода
|
Содержит все функции генерации машинного кода.
|
||||||
|
Фиксированные инструкции вынесены в kvs_pass2_encoder_fixsize.py.
|
||||||
|
Здесь остаются: parse_operand, parse_memory_operand, инструкции с адресацией, диспетчер.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
from kvs_data import INSTRUCTIONS, REGISTERS, get_reg_info
|
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):
|
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
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# ========== MOV С ПАМЯТЬЮ ==========
|
||||||
|
|
||||||
def encode_mov_reg_mem_absolute(reg_info, mem_info, current_pos, vaddr_text):
|
def encode_mov_reg_mem_absolute(reg_info, mem_info, current_pos, vaddr_text):
|
||||||
"""
|
"""
|
||||||
Кодирует MOV reg, [addr]
|
Кодирует 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])
|
reg_info = get_reg_info(operands[0])
|
||||||
mem_operand = operands[1]
|
mem_operand = operands[1]
|
||||||
|
|
||||||
# Пытаемся разобрать операнд памяти
|
|
||||||
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data, vaddr_bnd)
|
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data, vaddr_bnd)
|
||||||
if mem_info and mem_info['type'] == 'absolute':
|
if mem_info and mem_info['type'] == 'absolute':
|
||||||
return encode_mov_reg_mem_absolute(reg_info, mem_info, current_pos, vaddr_text)
|
return encode_mov_reg_mem_absolute(reg_info, mem_info, current_pos, vaddr_text)
|
||||||
|
|
||||||
# TODO: другие типы адресации
|
|
||||||
print(f"Предупреждение: сложная адресация '{mem_operand}' пока не поддерживается", file=sys.stderr)
|
print(f"Предупреждение: сложная адресация '{mem_operand}' пока не поддерживается", file=sys.stderr)
|
||||||
return b'\x90' * 3
|
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]
|
mem_operand = operands[0]
|
||||||
reg_info = get_reg_info(operands[1])
|
reg_info = get_reg_info(operands[1])
|
||||||
|
|
||||||
# Пытаемся разобрать операнд памяти
|
|
||||||
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data, vaddr_bnd)
|
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data, vaddr_bnd)
|
||||||
if mem_info and mem_info['type'] == 'absolute':
|
if mem_info and mem_info['type'] == 'absolute':
|
||||||
return encode_mov_mem_reg_absolute(reg_info, mem_info, current_pos, vaddr_text)
|
return encode_mov_mem_reg_absolute(reg_info, mem_info, current_pos, vaddr_text)
|
||||||
|
|
||||||
# TODO: другие типы адресации
|
|
||||||
print(f"Предупреждение: сложная адресация '{mem_operand}' пока не поддерживается", file=sys.stderr)
|
print(f"Предупреждение: сложная адресация '{mem_operand}' пока не поддерживается", file=sys.stderr)
|
||||||
return b'\x90' * 3
|
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])
|
reg_info = get_reg_info(operands[0])
|
||||||
mem_operand = operands[1]
|
mem_operand = operands[1]
|
||||||
|
|
||||||
# Пытаемся разобрать операнд памяти
|
|
||||||
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data, vaddr_bnd)
|
mem_info = parse_memory_operand(mem_operand, labels, label_sections, vaddr_text, vaddr_data, vaddr_bnd)
|
||||||
if mem_info and mem_info['type'] == 'absolute':
|
if mem_info and mem_info['type'] == 'absolute':
|
||||||
target_addr = mem_info['address']
|
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
|
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):
|
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
|
return code
|
||||||
|
|
||||||
|
|
||||||
def encode_mov_reg_reg(operands):
|
# ========== MOVZX/MOVSX (зависят от parse_operand) ==========
|
||||||
"""
|
|
||||||
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, vaddr_bnd=None):
|
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
|
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):
|
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
|
return code
|
||||||
|
|
||||||
|
|
||||||
def encode_cmp_reg_reg(mnemonic, operands):
|
# ========== ADD/SUB reg, imm (зависит от parse_operand) ==========
|
||||||
"""
|
|
||||||
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, vaddr_bnd=None):
|
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
|
return code
|
||||||
|
|
||||||
|
|
||||||
def encode_add_sub_reg_reg(mnemonic, operands):
|
# ========== ПЕРЕХОДЫ И ВЫЗОВЫ (зависят от parse_operand) ==========
|
||||||
"""
|
|
||||||
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, vaddr_bnd=None):
|
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
|
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):
|
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
|
||||||
3
todo.txt
3
todo.txt
|
|
@ -248,4 +248,5 @@ Pass2 (шаг 5):
|
||||||
|
|
||||||
|
|
||||||
избавиться от ре и перенести таблицу фиксированных размеров
|
избавиться от ре и перенести таблицу фиксированных размеров
|
||||||
вынести работу с памятью из второго прохода в отдельный энкодер
|
вынести работу с памятью из второго прохода в отдельный энкодер
|
||||||
|
изучить работу с кучей
|
||||||
Loading…
Reference in a new issue