однотабличная сборка

This commit is contained in:
mzhoot 2026-05-23 08:52:52 +03:00
parent 6400d6105a
commit 3a04dc5447
42 changed files with 1650 additions and 4355 deletions

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
"""kvs_build.py
Главный сборочный скрипт КВС
Последовательно запускает все этапы компиляции
"""
@ -23,17 +23,18 @@ if __name__ == "__main__":
tokens_file = base_name + ".токены"
ast_file = base_name + ".аст"
pass1_file = base_name + ".проход1"
csv_file = base_name + ".csv"
elf_file = base_name + ".elf"
stages = [
("kvs_lexer.py", [source_file, tokens_file], "Лексический анализ"),
("kvs_parser.py", [tokens_file, ast_file], "Парсинг"),
("kvs_pass1.py", [ast_file, pass1_file], "Первый проход"),
("kvs_pass2.py", [ast_file, pass1_file, csv_file], "Второй проход и генерация CSV"),
("kvs_verify.py", [pass1_file, csv_file], "Проверка размеров инструкций"),
("kvs_builder.py", [csv_file, pass1_file, elf_file], "Сборка ELF"),
("kvs_pass1.py", [ast_file, csv_file], "Первый проход: генерация кода и CSV"),
("kvs_pass2.py", [csv_file], "2 проход"),
("kvs_pass3.py", [ast_file, csv_file], "3 проход"),
("kvs_pass4.py", [csv_file], "4 проход"),
#("kvs_pass2.py", [csv_file], "Второй проход: разрешение меток"),
("kvs_builder.py", [csv_file, elf_file], "Сборка ELF"),
]
for script, args, description in stages:
@ -48,10 +49,9 @@ if __name__ == "__main__":
print(result.stdout)
sys.exit(1)
# Для верификатора показываем stdout (там детали проверки)
if result.stdout:
print(result.stdout)
print(f"\n=== Компиляция успешно завершена ===")
print(f"Исполняемый файл: {elf_file}")
print(f"Запустить: ./{elf_file}")
#print(f"\n=== Компиляция успешно завершена ===")
#print(f"Исполняемый файл: {elf_file}")
#print(f"Запустить: ./{elf_file}")

View file

@ -2,216 +2,103 @@
# -*- coding: utf-8 -*-
"""
Сборщик ELF из CSV
kvs_builder.py - Сборка ELF из CSV таблицы
Читает CSV, берёт колонки 'адрес' и 'рассчитанный_байт',
заполняет пропуски в адресах нулями и записывает выходной файл
"""
import sys
import struct
import csv
import os
sys.path.insert(0, '.')
from kvs_data import PAGE_SIZE, align_up, SHT_NOBITS, SHF_WRITE, SHF_ALLOC
import stat
def read_csv(input_file, vaddr_text, vaddr_data, text_size, data_size):
"""Загружает байты из CSV используя точные виртуальные адреса"""
text_bytes = bytearray(text_size)
data_bytes = bytearray(data_size)
def read_csv(csv_file):
"""Читает CSV и возвращает список адресов и байтов"""
addresses = []
bytes_list = []
with open(input_file, 'r', encoding='utf-8') as f:
next(f)
for line in f:
line = line.strip()
if not line:
continue
parts = line.split(';')
if len(parts) < 2:
continue
addr_str = parts[0]
byte_str = parts[1]
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.reader(f, delimiter=';')
headers = next(reader)
# Находим индексы нужных колонок
try:
addr_idx = headers.index('адрес')
byte_idx = headers.index('рассчитанный_байт')
except ValueError as e:
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
sys.exit(1)
for row in reader:
addr_str = row[addr_idx].strip()
byte_str = row[byte_idx].strip()
try:
if addr_str and addr_str.startswith('0x'):
addr = int(addr_str, 16)
byte_val = int(byte_str, 16)
except ValueError:
continue
if addr >= vaddr_data:
offset = addr - vaddr_data
if 0 <= offset < data_size:
data_bytes[offset] = byte_val
elif addr >= vaddr_text:
offset = addr - vaddr_text
if 0 <= offset < text_size:
text_bytes[offset] = byte_val
addresses.append(addr)
if byte_str and byte_str.startswith('0x'):
bytes_list.append(int(byte_str, 16))
else:
bytes_list.append(0)
# Заменяем хвостовые нули на NOP'ы (0x90)
# Находим последний ненулевой байт
last_nonzero = -1
for i in range(len(text_bytes) - 1, -1, -1):
if text_bytes[i] != 0:
last_nonzero = i
break
if last_nonzero >= 0 and last_nonzero < len(text_bytes) - 1:
for i in range(last_nonzero + 1, len(text_bytes)):
text_bytes[i] = 0x90
return text_bytes, data_bytes
return addresses, bytes_list
def read_pass1(input_file):
data = {}
labels = {}
with open(input_file, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line:
continue
parts = line.split(':')
if parts[0] == "PARAM":
key = parts[1]
value = parts[2]
if value.isdigit():
value = int(value)
data[key] = value
elif parts[0] == "LABEL":
label = parts[1]
pos = int(parts[3])
labels[label] = pos
return data, labels
def create_elf(text_bytes, data_bytes, pass1_data, labels, output_file):
vaddr_text = pass1_data.get("vaddr_text", 0x401000)
text_size = pass1_data.get("text_size", len(text_bytes))
data_size = pass1_data.get("data_size", len(data_bytes))
bnd_size = pass1_data.get("bnd_size", 0)
def build_file(addresses, bytes_list, output_file):
"""Собирает файл, заполняя пропуски в адресах нулями"""
if not addresses:
print("Нет данных для сборки")
return False
# Вычисляем виртуальные адреса
vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE)
vaddr_bnd = pass1_data.get("vaddr_bnd", align_up(vaddr_data + data_size, PAGE_SIZE))
# Определяем размер файла (максимальный адрес + 1)
max_addr = max(addresses)
file_size = max_addr + 1
offset_text = pass1_data.get("offset_text", 0x1000)
offset_data = align_up(offset_text + len(text_bytes), PAGE_SIZE)
offset_comment = pass1_data.get("offset_comment", align_up(offset_data + len(data_bytes), 1))
shstrtab_offset = pass1_data.get("shstrtab_offset", align_up(offset_comment + 32, 8))
shdr_offset = pass1_data.get("shdr_offset", align_up(shstrtab_offset + 32, 16))
entry_point_name = pass1_data.get("entry_point", "_start")
# Создаём буфер, заполненный нулями
buffer = bytearray(file_size)
entry_addr = vaddr_text + labels.get(entry_point_name, 0)
# Заполняем байты по известным адресам
for addr, byte_val in zip(addresses, bytes_list):
buffer[addr] = byte_val
comment_content = "Сборщик КВС".encode('utf-8') + b'\x00'
# Записываем файл
with open(output_file, 'wb') as f:
f.write(buffer)
# shstrtab с учётом .bss
if bnd_size > 0:
shstrtab_content = b"\x00.text\x00.data\x00.bss\x00.comment\x00.shstrtab\x00"
else:
shstrtab_content = b"\x00.text\x00.data\x00.comment\x00.shstrtab\x00"
# Добавляем права на исполнение (chmod +x)
st = os.stat(output_file)
os.chmod(output_file, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
elf_header_size = 64
ph_size = 56
ph_num = 3
shdr_size = 64
shdr_num = 5 + (1 if bnd_size > 0 else 0) # 5 базовых + .bss если есть
file_size = shdr_offset + shdr_num * shdr_size
elf_data = bytearray(file_size)
# ELF header
e_ident = b"\x7fELF\x02\x01\x01\x00" + b"\x00" * 8
elf_header = struct.pack(
'<16sHHIQQQIHHHHHH',
e_ident, 2, 0x3e, 1, entry_addr, elf_header_size, shdr_offset,
0, elf_header_size, ph_size, ph_num, shdr_size, shdr_num, 4
)
elf_data[0:64] = elf_header
def phdr(p_type, p_flags, p_offset, p_vaddr, p_filesz, p_memsz):
return struct.pack('<IIQQQQQQ',
p_type, p_flags, p_offset, p_vaddr, p_vaddr,
p_filesz, p_memsz, PAGE_SIZE
)
# Program headers
ph0 = phdr(1, 4, 0, 0x400000, elf_header_size + ph_num * ph_size, PAGE_SIZE)
ph1 = phdr(1, 5, offset_text, vaddr_text, len(text_bytes), align_up(len(text_bytes), PAGE_SIZE))
if bnd_size > 0:
data_segment_filesz = len(data_bytes)
# memsz должно покрывать от vaddr_data до конца .bss
bss_end = vaddr_bnd + bnd_size
data_segment_memsz = align_up(bss_end - vaddr_data, PAGE_SIZE)
ph2 = phdr(1, 6, offset_data, vaddr_data, data_segment_filesz, data_segment_memsz)
else:
ph2 = phdr(1, 6, offset_data, vaddr_data, len(data_bytes), align_up(len(data_bytes), PAGE_SIZE))
phdrs = ph0 + ph1 + ph2
elf_data[elf_header_size : elf_header_size + len(phdrs)] = phdrs
# Данные секций
elf_data[offset_text : offset_text + len(text_bytes)] = text_bytes
elf_data[offset_data : offset_data + len(data_bytes)] = data_bytes
elf_data[offset_comment : offset_comment + len(comment_content)] = comment_content
elf_data[shstrtab_offset : shstrtab_offset + len(shstrtab_content)] = shstrtab_content
def shdr(name_idx, sh_type, flags, addr, offset, size, addralign=1):
return struct.pack('<IIQQQQIIQQ',
name_idx, sh_type, flags, addr, offset, size,
0, 0, addralign, 0
)
# Индексы имён в shstrtab зависят от наличия .bss
if bnd_size > 0:
name_text = 1 # ".text"
name_data = 7 # ".data"
name_bss = 13 # ".bss"
name_comment = 18 # ".comment"
name_shstrtab = 27 # ".shstrtab"
else:
name_text = 1
name_data = 7
name_comment = 13
name_shstrtab = 22
# Section headers
sh0 = shdr(0, 0, 0, 0, 0, 0) # NULL
sh1 = shdr(name_text, 1, 6, vaddr_text, offset_text, len(text_bytes), 16) # .text
sh2 = shdr(name_data, 1, 3, vaddr_data, offset_data, len(data_bytes), 8) # .data
if bnd_size > 0:
sh3 = shdr(name_bss, SHT_NOBITS, SHF_WRITE | SHF_ALLOC, vaddr_bnd, 0, bnd_size, 16) # .bss
sh4 = shdr(name_comment, 1, 0, 0, offset_comment, len(comment_content), 1) # .comment
sh5 = shdr(name_shstrtab, 3, 0, 0, shstrtab_offset, len(shstrtab_content), 1) # .shstrtab
shdrs = sh0 + sh1 + sh2 + sh3 + sh4 + sh5
else:
sh3 = shdr(name_comment, 1, 0, 0, offset_comment, len(comment_content), 1)
sh4 = shdr(name_shstrtab, 3, 0, 0, shstrtab_offset, len(shstrtab_content), 1)
shdrs = sh0 + sh1 + sh2 + sh3 + sh4
elf_data[shdr_offset : shdr_offset + len(shdrs)] = shdrs
with open(output_file, "wb") as f:
f.write(elf_data)
os.chmod(output_file, 0o755)
print(f"Сборщик: ELF-файл создан: {output_file}")
print(f" .text: {len(text_bytes)} байт, адрес: 0x{vaddr_text:x}")
print(f" .data: {len(data_bytes)} байт, адрес: 0x{vaddr_data:x}")
if bnd_size > 0:
print(f" .bss: {bnd_size} байт, адрес: 0x{vaddr_bnd:x}")
return True
if __name__ == "__main__":
if len(sys.argv) != 4:
print("Использование: python kvs_builder.py <вход.csv> <вход.проход1> <выход.elf>")
def main():
if len(sys.argv) != 3:
print("Использование: python kvs_builder.py <входной.csv> <выходной.elf>")
sys.exit(1)
pass1_data, labels = read_pass1(sys.argv[2])
vaddr_text = pass1_data["vaddr_text"]
text_size = pass1_data["text_size"]
data_size = pass1_data["data_size"]
csv_file = sys.argv[1]
elf_file = sys.argv[2]
# Вычисляем vaddr_data
vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE)
print(f"\n=== Сборка ELF из CSV ===")
print(f"Чтение CSV: {csv_file}")
text_bytes, data_bytes = read_csv(sys.argv[1], vaddr_text, vaddr_data, text_size, data_size)
create_elf(text_bytes, data_bytes, pass1_data, labels, sys.argv[3])
addresses, bytes_list = read_csv(csv_file)
print(f"Найдено {len(addresses)} записей")
if build_file(addresses, bytes_list, elf_file):
print(f"\n=== Сборка завершена ===")
print(f" Записей в CSV: {len(addresses)}")
print(f" Размер файла: {max(addresses) + 1} байт (0x{max(addresses) + 1:x})")
print(f" Выходной файл: {elf_file}")
print(f"\n Исполняемый файл готов!")
print(f" Запустить: ./{elf_file}")
else:
print("Ошибка при сборке")
sys.exit(1)
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load diff

View file

@ -3,347 +3,231 @@
"""
Второй проход КВС
Генерирует машинный код и создаёт CSV-файл
- Собирает адреса всех приводящих меток (поддерживает несколько меток через запятую)
- Заменяет заглушки в уводящих адресах на реальные адреса
- Записывает рассчитанные значения в колонку 'рассчитанный_уводящий_адрес' (файловое смещение)
- Формирует команду с подставленными адресами в колонку 'команда_со_значениями' (виртуальный адрес)
- Пропускает заглушки, которые не найдены (возможно это константы)
- Выводит статистику по неразрешённым заглушкам
"""
import sys
import struct
sys.path.insert(0, '.')
from kvs_data import PAGE_SIZE, align_up
from kvs_pass2_encoder import encode_instruction, parse_operand
import csv
from collections import Counter
def unescape_string(s):
"""Преобразует escape-последовательности в реальные символы"""
result = []
i = 0
while i < len(s):
if s[i] == '\\' and i + 1 < len(s):
if s[i + 1] == 'n':
result.append('\n')
elif s[i + 1] == 't':
result.append('\t')
elif s[i + 1] == 'r':
result.append('\r')
def read_csv(csv_file):
"""Читает CSV файл и возвращает список записей и заголовки"""
entries = []
headers = []
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.reader(f, delimiter=';')
headers = next(reader)
for row in reader:
entries.append(row)
return headers, entries
def get_virtual_addresses(entries, headers):
"""
Извлекает виртуальные адреса секций из заголовка CSV
Возвращает (vaddr_text, vaddr_data)
"""
vaddr_text = 0x401000
vaddr_data = 0x402000
try:
source_idx = headers.index('исходная_команда')
calc_target_idx = headers.index('рассчитанный_уводящий_адрес')
except ValueError:
return vaddr_text, vaddr_data
for row in entries:
source = row[source_idx].strip()
calc_target = row[calc_target_idx].strip()
if 'p_vaddr (text)' in source and calc_target:
parts = calc_target.split('=')
if len(parts) >= 2:
addr_str = parts[1].strip()
if addr_str.startswith('0x'):
vaddr_text = int(addr_str, 16)
elif 'p_vaddr (data)' in source and calc_target:
parts = calc_target.split('=')
if len(parts) >= 2:
addr_str = parts[1].strip()
if addr_str.startswith('0x'):
vaddr_data = int(addr_str, 16)
return vaddr_text, vaddr_data
def collect_labels(entries, headers, vaddr_text, vaddr_data):
"""
Собирает адреса всех приводящих меток.
Возвращает два словаря:
- labels_file: имя метки -> файловое смещение
- labels_virt: имя метки -> виртуальный адрес
"""
labels_file = {} # имя метки -> файловое смещение
labels_virt = {} # имя метки -> виртуальный адрес
try:
label_idx = headers.index('приводящая_метка')
addr_idx = headers.index('адрес')
segment_idx = headers.index('сегмент')
except ValueError as e:
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
sys.exit(1)
for row in entries:
label_str = row[label_idx].strip()
if label_str:
addr_str = row[addr_idx].strip()
if addr_str.startswith('0x'):
file_addr = int(addr_str, 16)
segment = row[segment_idx].strip()
# Вычисляем виртуальный адрес
if segment == '.text':
virt_addr = vaddr_text + (file_addr - 0x1000)
elif segment == '.data':
virt_addr = vaddr_data + (file_addr - 0x2000)
else:
virt_addr = file_addr
# Разделяем несколько меток через запятую
for label_name in label_str.split(','):
label_name = label_name.strip()
if label_name:
labels_file[label_name] = file_addr
labels_virt[label_name] = virt_addr
return labels_file, labels_virt
def resolve_targets(entries, headers, labels_file, labels_virt):
"""
Заменяет уводящие адреса-заглушки на реальные адреса
- рассчитанный_уводящий_адрес: файловое смещение
- команда_со_значениями: виртуальный адрес
"""
try:
target_idx = headers.index('уводящий_адрес')
calc_target_idx = headers.index('рассчитанный_уводящий_адрес')
source_idx = headers.index('исходная_команда')
source_with_values_idx = headers.index('команда_со_значениями')
except ValueError as e:
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
sys.exit(1)
resolved = [] # (имя_метки, файловый_адрес, виртуальный_адрес)
unresolved = [] # имя_метки
for row in entries:
target = row[target_idx].strip()
if target and target.startswith('ЗАГЛУШКА '):
label_name = target.replace('ЗАГЛУШКА ', '').strip()
if label_name in labels_file:
file_addr = labels_file[label_name]
virt_addr = labels_virt[label_name]
file_hex = f"0x{file_addr:08x}"
virt_hex = f"0x{virt_addr:08x}"
# Файловое смещение в рассчитанный_уводящий_адрес
row[calc_target_idx] = file_hex
resolved.append((label_name, file_addr, virt_addr))
# Виртуальный адрес в команда_со_значениями
source_cmd = row[source_idx].strip()
if source_cmd:
cmd_with_addr = source_cmd.replace(label_name, virt_hex)
row[source_with_values_idx] = cmd_with_addr
else:
result.append(s[i])
result.append(s[i + 1])
i += 2
else:
result.append(s[i])
i += 1
return ''.join(result)
def read_ast(input_file):
"""Читает AST из файла"""
ast_lines = []
with open(input_file, 'r', encoding='utf-8') as f:
for line in f:
ast_lines.append(line.strip())
return ast_lines
def read_pass1(input_file):
"""
Читает результаты первого прохода:
- PARAM: параметры компоновки (размеры, адреса)
- LABEL: метки и их позиции
- SYMBOL: константы
"""
data = {}
labels = {}
label_sections = {}
symbols = {}
unresolved.append(label_name)
row[calc_target_idx] = ""
with open(input_file, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line:
continue
parts = line.split(':')
if parts[0] == "PARAM":
key = parts[1]
value = parts[2]
if value.isdigit() or (value.startswith('-') and value[1:].isdigit()):
value = int(value)
data[key] = value
elif parts[0] == "LABEL":
label = parts[1]
sec = parts[2]
pos = int(parts[3])
labels[label] = pos
label_sections[label] = sec
elif parts[0] == "SYMBOL":
name = parts[1]
value = int(parts[2])
symbols[name] = value
return data, labels, label_sections, symbols
return resolved, unresolved
# ========== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ПАРСИНГА AST ==========
def parse_ast_line(line):
"""
Универсальный разбор строки AST.
Возвращает (тип, словарь_полей).
Форматы AST:
- DIRECTIVE:имя
- DIRECTIVE:имя:секция
- DIRECTIVE:имя:секция:данные
- DIRECTIVE:имя:имя_константы:значение
- LABEL:имя:секция
- INSTR:мнемоника:секция:операнд1,операнд2,...
Операнды могут содержать двоеточия (MEM:reg_indirect:рбикс).
Поэтому для INSTR используется специальный разбор: первые 3 двоеточия
отделяют служебные поля, остальное операнды.
"""
if not line:
return None, {}
line_type = line.split(':')[0]
if line_type == "INSTR":
# Формат: INSTR:мнемоника:секция:операнды
# Находим первые три двоеточия
first_colon = line.find(':')
second_colon = line.find(':', first_colon + 1)
third_colon = line.find(':', second_colon + 1)
if first_colon == -1 or second_colon == -1 or third_colon == -1:
return "INSTR", {}
mnemonic = line[first_colon + 1 : second_colon]
section = line[second_colon + 1 : third_colon]
operands_str = line[third_colon + 1 :]
operands = []
if operands_str:
operands = operands_str.split(',')
return "INSTR", {
'mnemonic': mnemonic,
'section': section,
'operands': operands,
'operands_str': operands_str
}
elif line_type == "DIRECTIVE":
parts = line.split(':')
directive = parts[1] if len(parts) > 1 else ""
if directive in ('.текст', '.данные', '.бнд'):
return "DIRECTIVE", {'directive': directive}
elif directive == '.глобал':
label = parts[2] if len(parts) > 2 else ""
return "DIRECTIVE", {'directive': directive, 'label': label}
elif directive in ('.строкауль', '.строка'):
sec = parts[2] if len(parts) > 2 else ""
s = parts[3] if len(parts) > 3 else ""
return "DIRECTIVE", {'directive': directive, 'section': sec, 'string': s}
elif directive == '.константа':
name = parts[2] if len(parts) > 2 else ""
value = parts[3] if len(parts) > 3 else ""
return "DIRECTIVE", {'directive': directive, 'name': name, 'value': value}
elif directive == '.байт':
sec = parts[2] if len(parts) > 2 else ""
bytes_str = parts[3] if len(parts) > 3 else ""
return "DIRECTIVE", {'directive': directive, 'section': sec, 'bytes': bytes_str}
elif directive in ('.резб', '.резс', '.рездс', '.резкс'):
sec = parts[2] if len(parts) > 2 else ""
count = parts[3] if len(parts) > 3 else "0"
return "DIRECTIVE", {'directive': directive, 'section': sec, 'count': count}
else:
return "DIRECTIVE", {'directive': directive}
elif line_type == "LABEL":
parts = line.split(':')
label_name = parts[1] if len(parts) > 1 else ""
sec = parts[2] if len(parts) > 2 else ""
return "LABEL", {'name': label_name, 'section': sec}
return line_type, {}
def save_csv(csv_file, headers, entries):
"""Сохраняет обновлённый CSV файл"""
with open(csv_file, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f, delimiter=';')
writer.writerow(headers)
writer.writerows(entries)
# ========== ОСНОВНОЙ КЛАСС ВТОРОГО ПРОХОДА ==========
class Pass2:
def __init__(self, pass1_data, labels, label_sections, symbols):
self.labels = labels
self.label_sections = label_sections
self.symbols = symbols
self.vaddr_text = pass1_data["vaddr_text"]
self.vaddr_data = pass1_data.get("vaddr_data", align_up(self.vaddr_text + pass1_data["text_size"], PAGE_SIZE))
self.vaddr_bnd = pass1_data.get("vaddr_bnd", self.vaddr_data + PAGE_SIZE)
self.position = {".text": 0, ".data": 0}
self.current_section = ".text"
self.csv_lines = []
self.data_bytes = {".text": bytearray(), ".data": bytearray()}
def get_target_addr(self, mnemonic, operands):
"""Вычисляет целевой адрес для инструкций перехода"""
jump_instructions = {
"переход", "короткий_переход", "вызвать", "цикл",
"переход_если_равно", "переход_если_неравно", "переход_если_меньше",
"переход_если_больше", "переход_если_меньше_или_равно", "переход_если_больше_или_равно",
"переход_если_перенос", "переход_если_нет_переноса", "переход_если_ноль", "переход_если_неоль",
"короткий_переход_если_равно", "короткий_переход_если_неравно", "короткий_переход_если_меньше",
"короткий_переход_если_больше", "короткий_переход_если_меньше_или_равно", "короткий_переход_если_больше_или_равно",
"короткий_переход_если_перенос", "короткий_переход_если_нет_переноса",
"короткий_переход_если_ноль", "короткий_переход_если_неоль"
}
try:
if mnemonic in jump_instructions:
target = parse_operand(operands[0], self.labels, self.label_sections,
self.symbols, self.vaddr_text, self.vaddr_data)
return hex(target)
elif mnemonic == "переместить_имм" and len(operands) >= 2:
op_str = operands[1]
if op_str in self.labels:
sec = self.label_sections[op_str]
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
return hex(addr)
elif op_str in self.symbols:
return hex(self.symbols[op_str])
except Exception:
return "ошибка"
return ""
def print_statistics(labels_count, resolved, unresolved, vaddr_text, vaddr_data):
"""Выводит статистику по разрешению меток"""
print(f"\n--- Статистика разрешения меток ---")
print(f" Виртуальный адрес .text: 0x{vaddr_text:x}")
print(f" Виртуальный адрес .data: 0x{vaddr_data:x}")
print(f" Всего приводящих меток: {labels_count}")
print(f" Разрешено заглушек: {len(resolved)}")
print(f" Не разрешено заглушек (возможно константы): {len(unresolved)}")
def process_line(self, line):
"""Обрабатывает одну строку AST"""
line_type, fields = parse_ast_line(line)
if resolved:
unique_resolved = {}
for name, file_addr, virt_addr in resolved:
if name not in unique_resolved:
unique_resolved[name] = (file_addr, virt_addr)
if line_type == "DIRECTIVE":
directive = fields.get('directive', '')
if directive == '.текст':
self.current_section = ".text"
elif directive == '.данные':
self.current_section = ".data"
elif directive in ('.строкауль', '.строка'):
s = fields.get('string', '')
real_s = unescape_string(s)
bstring = real_s.encode('utf-8')
if directive == '.строкауль':
bstring += b'\x00'
original_cmd = f'{directive} "{s}"'
start_addr = self.vaddr_data + self.position[".data"]
for i, byte in enumerate(bstring):
addr = start_addr + i
byte_hex = "{:02X}".format(byte)
cmd = original_cmd if i == 0 else ""
self.csv_lines.append((hex(addr), byte_hex, "", cmd))
self.data_bytes[".data"] += bstring
self.position[".data"] += len(bstring)
elif directive == '.байт':
bytes_str = fields.get('bytes', '')
if bytes_str:
byte_values = bytes_str.split(',')
original_cmd = f".байт {bytes_str}"
start_addr = self.vaddr_data + self.position[".data"]
for i, byte_str in enumerate(byte_values):
if byte_str.startswith('0x'):
val = int(byte_str, 16)
elif byte_str.isdigit() or (byte_str.startswith('-') and byte_str[1:].isdigit()):
val = int(byte_str)
else:
continue
addr = start_addr + i
byte_hex = "{:02X}".format(val & 0xFF)
cmd = original_cmd if i == 0 else ""
self.csv_lines.append((hex(addr), byte_hex, "", cmd))
self.data_bytes[".data"].append(val & 0xFF)
self.position[".data"] += len(byte_values)
elif line_type == "LABEL":
label_name = fields.get('name', '')
sec = fields.get('section', '')
if label_name in self.labels:
self.position[sec] = self.labels[label_name]
elif line_type == "INSTR":
mnemonic = fields.get('mnemonic', '')
sec = fields.get('section', '')
operands = fields.get('operands', [])
if operands:
original_cmd = f"{mnemonic} {', '.join(operands)}"
else:
original_cmd = mnemonic
current_pos = self.position[sec]
code = encode_instruction(mnemonic, operands, self.labels, self.label_sections,
self.symbols, self.vaddr_text, self.vaddr_data, current_pos,
self.vaddr_bnd)
target_addr = self.get_target_addr(mnemonic, operands)
start_addr = (self.vaddr_text if sec == ".text" else self.vaddr_data) + current_pos
for i, byte in enumerate(code):
addr = start_addr + i
byte_hex = "{:02X}".format(byte)
cmd = original_cmd if i == 0 else ""
addr_target = target_addr if i == 0 else ""
self.csv_lines.append((hex(addr), byte_hex, addr_target, cmd))
self.data_bytes[sec] += code
self.position[sec] += len(code)
print(f"\n--- Разрешённые заглушки (первые 20) ---")
for i, (name, (file_addr, virt_addr)) in enumerate(list(unique_resolved.items())[:20]):
print(f" {name} -> файл:0x{file_addr:08x}, вирт:0x{virt_addr:08x}")
if len(unique_resolved) > 20:
print(f" ... и ещё {len(unique_resolved) - 20}")
def process_all(self, ast_lines):
"""Обрабатывает все строки AST"""
for line in ast_lines:
self.process_line(line)
return self.csv_lines
if unresolved:
unresolved_counts = Counter(unresolved)
print(f"\n--- Неразрешённые заглушки (возможно константы) ---")
for name, count in sorted(unresolved_counts.items(), key=lambda x: x[1], reverse=True)[:20]:
print(f" {name}: {count} раз(а)")
if len(unresolved_counts) > 20:
print(f" ... и ещё {len(unresolved_counts) - 20} различных имён")
def write_csv(csv_lines, output_file):
"""Записывает сгенерированные байты в CSV файл"""
with open(output_file, 'w', encoding='utf-8') as f:
f.write("адрес;байт;целевой_адрессходная_команда\n")
for addr, byte, target, cmd in csv_lines:
if cmd and (';' in cmd or '\n' in cmd):
cmd = '"' + cmd.replace('"', '""') + '"'
f.write(f"{addr};{byte};{target};{cmd}\n")
def main():
if len(sys.argv) != 2:
print("Использование: python kvs_pass2.py <входной.csv>")
sys.exit(1)
csv_file = sys.argv[1]
print(f"\n=== Второй проход КВС ===")
print(f"Чтение CSV: {csv_file}")
headers, entries = read_csv(csv_file)
vaddr_text, vaddr_data = get_virtual_addresses(entries, headers)
print(f"Виртуальный адрес .text: 0x{vaddr_text:x}")
print(f"Виртуальный адрес .data: 0x{vaddr_data:x}")
print(f"\n--- Сбор приводящих меток ---")
labels_file, labels_virt = collect_labels(entries, headers, vaddr_text, vaddr_data)
print(f"Найдено приводящих меток: {len(labels_file)}")
if labels_file:
print(f"\n--- Примеры приводящих меток (первые 20) ---")
for i, name in enumerate(list(labels_file.keys())[:20]):
print(f" {name} -> файл:0x{labels_file[name]:08x}, вирт:0x{labels_virt[name]:08x}")
if len(labels_file) > 20:
print(f" ... и ещё {len(labels_file) - 20}")
print(f"\n--- Разрешение уводящих адресов и формирование команд ---")
resolved, unresolved = resolve_targets(entries, headers, labels_file, labels_virt)
print_statistics(len(labels_file), resolved, unresolved, vaddr_text, vaddr_data)
save_csv(csv_file, headers, entries)
print(f"\nCSV сохранен: {csv_file}")
if __name__ == "__main__":
if len(sys.argv) != 4:
print("Использование: python kvs_pass2.py <вход.аст> <вход.проход1> <выход.csv>")
sys.exit(1)
ast_lines = read_ast(sys.argv[1])
pass1_data, labels, label_sections, symbols = read_pass1(sys.argv[2])
pass2 = Pass2(pass1_data, labels, label_sections, symbols)
csv_lines = pass2.process_all(ast_lines)
write_csv(csv_lines, sys.argv[3])
print(f"Проход 2: {len(csv_lines)} строк CSV записано в {sys.argv[3]}")
print(f" .text: {pass2.position['.text']} байт, виртуальный адрес: 0x{pass2.vaddr_text:x}")
print(f" .data: {pass2.position['.data']} байт, виртуальный адрес: 0x{pass2.vaddr_data:x}")
main()

141
kvs_pass3.py Normal file
View file

@ -0,0 +1,141 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Третий проход КВС
- Читает AST для получения констант
- Заменяет имена констант в 'исходная_команда' на их числовые значения
- Записывает результат в колонку 'команда_со_значениями'
- Поддерживает константы в операндах (как непосредственные значения)
"""
import sys
import csv
def read_ast(ast_file):
"""Читает AST файл и извлекает константы"""
symbols = {} # имя константы -> значение
with open(ast_file, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line:
continue
parts = line.split(':')
if parts[0] == "DIRECTIVE" and len(parts) >= 4:
directive = parts[1]
if directive == '.константа':
name = parts[2]
value_str = parts[3]
if value_str.startswith('0x') or value_str.startswith('0X'):
value = int(value_str, 16)
else:
value = int(value_str)
symbols[name] = value
print(f" константа: {name} = {value}")
return symbols
def read_csv(csv_file):
"""Читает CSV файл и возвращает список записей и заголовки"""
entries = []
headers = []
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.reader(f, delimiter=';')
headers = next(reader)
for row in reader:
entries.append(row)
return headers, entries
def substitute_constants(entries, headers, symbols):
"""Заменяет константы в исходной команде на их значения"""
try:
source_idx = headers.index('исходная_команда')
source_with_values_idx = headers.index('команда_со_значениями')
except ValueError as e:
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
sys.exit(1)
substituted_count = 0
for row in entries:
source = row[source_idx].strip()
if not source:
continue
# Копируем исходную команду
new_source = source
# Заменяем константы в команде
for name, value in symbols.items():
if name in new_source:
# Заменяем имя константы на её значение
new_source = new_source.replace(name, str(value))
# Если команда изменилась, записываем в колонку команда_со_значениями
if new_source != source:
row[source_with_values_idx] = new_source
substituted_count += 1
return substituted_count
def save_csv(csv_file, headers, entries):
"""Сохраняет обновлённый CSV файл"""
with open(csv_file, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f, delimiter=';')
writer.writerow(headers)
writer.writerows(entries)
def print_statistics(symbols_count, substituted_count, symbols):
"""Выводит статистику по заменам констант"""
print(f"\n--- Статистика замены констант ---")
print(f" Всего констант в AST: {symbols_count}")
print(f" Заменено в командах: {substituted_count}")
if symbols:
print(f"\n--- Найденные константы ---")
for name, value in sorted(symbols.items()):
print(f" {name} = {value}")
def main():
if len(sys.argv) != 3:
print("Использование: python kvs_pass3.py <аст.файл> <входной.csv>")
print(" <аст.файл> - файл с AST (например, программа.аст)")
print(" <входной.csv> - CSV файл для обновления")
sys.exit(1)
ast_file = sys.argv[1]
csv_file = sys.argv[2]
print(f"\n=== Третий проход КВС ===")
print(f"Чтение AST: {ast_file}")
# Читаем константы из AST
symbols = read_ast(ast_file)
print(f"Найдено констант: {len(symbols)}")
print(f"\nЧтение CSV: {csv_file}")
headers, entries = read_csv(csv_file)
print(f"\n--- Замена констант в командах ---")
substituted_count = substitute_constants(entries, headers, symbols)
print_statistics(len(symbols), substituted_count, symbols)
# Сохраняем результат
save_csv(csv_file, headers, entries)
print(f"\nCSV сохранен: {csv_file}")
print(f"Колонка 'команда_со_значениями' обновлена")
if __name__ == "__main__":
main()

262
kvs_pass4.py Normal file
View file

@ -0,0 +1,262 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Четвёртый проход КВС
- Перекодирует инструкции, используя подставленные значения
- Смотрит колонки 'команда_со_значениями' и 'рассчитанный_уводящий_адрес'
- Записывает перекодированные байты в колонку 'рассчитанный_байт'
"""
import sys
import csv
import struct
sys.path.insert(0, '.')
from kvs_data import PAGE_SIZE, text_vaddr_base, align_up
from kvs_encoder import encode_instruction
# ========== ГЛОБАЛЬНОЕ СОСТОЯНИЕ ==========
vaddr_text = text_vaddr_base
vaddr_data = None
vaddr_bnd = None
labels = {} # имя метки -> адрес
label_sections = {} # имя метки -> секция
symbols = {} # имя константы -> значение
def read_csv(csv_file):
"""Читает CSV файл и возвращает список записей и заголовки"""
entries = []
headers = []
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.reader(f, delimiter=';')
headers = next(reader)
for row in reader:
entries.append(row)
return headers, entries
def parse_command(cmd_str):
"""Разбирает команду вида 'мнемоника операнд1, операнд2, ...'"""
if not cmd_str:
return None, []
parts = cmd_str.split(' ', 1)
mnemonic = parts[0]
operands = []
if len(parts) > 1 and parts[1]:
# Разбираем операнды, разделённые запятыми
operands = [op.strip() for op in parts[1].split(',')]
return mnemonic, operands
def collect_labels_from_csv(entries, headers):
"""Собирает метки из CSV для перекодирования"""
global labels, label_sections, vaddr_data, vaddr_bnd
try:
label_idx = headers.index('приводящая_метка')
addr_idx = headers.index('адрес')
segment_idx = headers.index('сегмент')
byte_idx = headers.index('байт')
except ValueError as e:
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
sys.exit(1)
# Сначала нужно определить виртуальные адреса секций
max_addr = 0
for row in entries:
addr_str = row[addr_idx].strip()
if addr_str.startswith('0x'):
addr = int(addr_str, 16)
if addr > max_addr:
max_addr = addr
segment = row[segment_idx].strip()
# Определяем vaddr_data по первому адресу в .data
if segment == '.data' and vaddr_data is None:
vaddr_data = addr
# Определяем vaddr_bnd по первому адресу в .bss
elif segment == '.bss' and vaddr_bnd is None:
vaddr_bnd = addr
if vaddr_data is None:
vaddr_data = align_up(vaddr_text + max_addr, PAGE_SIZE)
if vaddr_bnd is None:
vaddr_bnd = align_up(vaddr_data + max_addr, PAGE_SIZE)
# Собираем метки
for row in entries:
label_str = row[label_idx].strip()
if label_str:
addr_str = row[addr_idx].strip()
if addr_str.startswith('0x'):
addr = int(addr_str, 16)
for label_name in label_str.split(','):
label_name = label_name.strip()
if label_name:
labels[label_name] = addr
# Определяем секцию по адресу
if addr >= vaddr_text and addr < vaddr_text + PAGE_SIZE:
label_sections[label_name] = '.text'
elif vaddr_data and addr >= vaddr_data and addr < vaddr_data + PAGE_SIZE:
label_sections[label_name] = '.data'
elif vaddr_bnd and addr >= vaddr_bnd:
label_sections[label_name] = '.bss'
def reencode_instructions(entries, headers):
"""Перекодирует инструкции, используя подставленные значения"""
try:
source_with_values_idx = headers.index('команда_со_значениями')
calc_target_idx = headers.index('рассчитанный_уводящий_адрес')
calc_byte_idx = headers.index('рассчитанный_байт')
addr_idx = headers.index('адрес')
segment_idx = headers.index('сегмент')
byte_idx = headers.index('байт')
except ValueError as e:
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
sys.exit(1)
reencoded_count = 0
error_count = 0
# Проходим по всем строкам
i = 0
while i < len(entries):
row = entries[i]
addr_str = row[addr_idx].strip()
if not addr_str.startswith('0x'):
i += 1
continue
addr = int(addr_str, 16)
segment = row[segment_idx].strip()
# Проверяем, есть ли команда для перекодирования
cmd = row[source_with_values_idx].strip()
calc_target = row[calc_target_idx].strip()
# Определяем, нужно ли перекодировать
need_reencode = False
if cmd:
# Есть команда с подставленными константами
need_reencode = True
elif calc_target and calc_target.startswith('0x'):
# Есть рассчитанный адрес для заглушки
# Нужно взять исходную команду и подставить адрес
source_idx = headers.index('исходная_команда')
source = row[source_idx].strip()
if source:
# Заменяем ЗАГЛУШКА имя на реальный адрес
target_addr = int(calc_target, 16)
cmd = source.replace('ЗАГЛУШКА', '').strip()
# Добавляем адрес как операнд
cmd = f"{cmd} 0x{target_addr:08x}"
need_reencode = True
if need_reencode and cmd:
try:
mnemonic, operands = parse_command(cmd)
if mnemonic:
# Вычисляем текущую позицию в секции
if segment == '.text':
current_pos = addr - vaddr_text
elif segment == '.data' and vaddr_data:
current_pos = addr - vaddr_data
else:
current_pos = 0
# Кодируем инструкцию
encoded = encode_instruction(
mnemonic, operands, labels, label_sections, symbols,
vaddr_text, vaddr_data if vaddr_data else 0,
current_pos, vaddr_bnd if vaddr_bnd else 0
)
# Записываем байты в колонку рассчитанный_байт
# Для много-байтовых инструкций записываем в последовательные строки
for j, byte in enumerate(encoded):
if i + j < len(entries):
entries[i + j][calc_byte_idx] = f"0x{byte:02x}"
else:
# Не хватает строк, создаём новую
# (в нормальной ситуации не должно происходить)
pass
reencoded_count += 1
# Пропускаем следующие строки, принадлежащие этой инструкции
# (обычно в CSV одна строка = один байт)
i += len(encoded)
continue
except Exception as e:
print(f"Ошибка перекодирования '{cmd}': {e}")
error_count += 1
# Записываем INT3 как заглушку
row[calc_byte_idx] = "0xcc"
i += 1
else:
# Если нет команды для перекодирования, просто копируем исходный байт
byte_str = row[byte_idx].strip()
if byte_str.startswith('0x'):
row[calc_byte_idx] = byte_str
i += 1
return reencoded_count, error_count
def save_csv(csv_file, headers, entries):
"""Сохраняет обновлённый CSV файл"""
with open(csv_file, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f, delimiter=';')
writer.writerow(headers)
writer.writerows(entries)
def print_statistics(reencoded_count, error_count):
"""Выводит статистику перекодирования"""
print(f"\n--- Статистика перекодирования ---")
print(f" Перекодировано инструкций: {reencoded_count}")
if error_count:
print(f" Ошибок: {error_count}")
def main():
if len(sys.argv) != 2:
print("Использование: python kvs_pass4.py <входной.csv>")
sys.exit(1)
csv_file = sys.argv[1]
print(f"\n=== Четвёртый проход КВС ===")
print(f"Чтение CSV: {csv_file}")
# Читаем CSV
headers, entries = read_csv(csv_file)
print(f"\n--- Сбор меток из CSV ---")
collect_labels_from_csv(entries, headers)
print(f"Найдено меток: {len(labels)}")
print(f"\n--- Перекодирование инструкций ---")
reencoded_count, error_count = reencode_instructions(entries, headers)
print_statistics(reencoded_count, error_count)
# Сохраняем результат
save_csv(csv_file, headers, entries)
print(f"\nCSV сохранен: {csv_file}")
print(f"Колонка 'рассчитанный_байт' обновлена")
if __name__ == "__main__":
main()

View file

@ -1,249 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Верификатор КВС
Сравнивает размеры инструкций из pass1 с реальными размерами из CSV.
Выводит расхождения и останавливает сборку при ошибках.
"""
import sys
# Если True — разрешает сборку, когда единственная ошибка это общий размер .text
# (расхождение до 16 байт считается допустимым)
ENABLE = False
ALLOW_TEXT_SIZE_MISMATCH = True
MAX_TEXT_SIZE_MISMATCH = 25
def read_pass1(input_file):
"""Читает pass1-файл: PARAM и LABEL"""
params = {}
labels = {}
label_sections = {}
with open(input_file, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line:
continue
parts = line.split(':')
if parts[0] == "PARAM":
key = parts[1]
value = parts[2]
if value.isdigit() or (value.startswith('-') and value[1:].isdigit()):
value = int(value)
params[key] = value
elif parts[0] == "LABEL":
label = parts[1]
sec = parts[2]
pos = int(parts[3])
labels[label] = pos
label_sections[label] = sec
return params, labels, label_sections
def read_csv(input_file):
"""
Читает CSV-файл.
Возвращает:
- instr_list: список инструкций с адресами и размерами
"""
instr_list = []
current_cmd = None
current_start = None
current_size = 0
with open(input_file, 'r', encoding='utf-8') as f:
header = f.readline()
for line in f:
line = line.strip()
if not line:
continue
parts = line.split(';')
if len(parts) < 2:
continue
addr_str = parts[0]
byte_str = parts[1]
cmd_str = parts[3] if len(parts) > 3 else ""
try:
addr = int(addr_str, 16)
except ValueError:
continue
if addr >= 0x402000:
break
if cmd_str:
if current_cmd is not None:
instr_list.append({
'cmd': current_cmd,
'start': current_start,
'size': current_size
})
current_cmd = cmd_str
current_start = addr
current_size = 1
else:
current_size += 1
if current_cmd is not None:
instr_list.append({
'cmd': current_cmd,
'start': current_start,
'size': current_size
})
return instr_list
def verify(pass1_file, csv_file):
"""Сравнивает pass1 и pass2, возвращает список ошибок"""
from kvs_data import FIXED_SIZE_INSTRUCTIONS, INSTRUCTIONS
params, labels, label_sections = read_pass1(pass1_file)
instr_list = read_csv(csv_file)
vaddr_text = params.get("vaddr_text", 0x401000)
text_size_pass1 = params.get("text_size", 0)
text_size_pass2 = sum(instr['size'] for instr in instr_list)
errors = []
warnings = []
print(f"Pass1 .text: {text_size_pass1} байт")
print(f"Pass2 .text: {text_size_pass2} байт")
print()
# Проверка общего размера
text_size_error = None
if text_size_pass1 != text_size_pass2:
diff = text_size_pass2 - text_size_pass1
text_size_error = f"Общий размер .text: pass1={text_size_pass1}, pass2={text_size_pass2} (разница {diff:+d} байт)"
if ALLOW_TEXT_SIZE_MISMATCH and abs(diff) <= MAX_TEXT_SIZE_MISMATCH:
warnings.append(text_size_error + " — допустимо, сборка продолжена")
else:
errors.append(text_size_error)
# Проверка позиций меток
print("Проверка позиций меток (.text):")
for label, pass1_offset in labels.items():
if label_sections.get(label) != ".text":
continue
pass1_addr = vaddr_text + pass1_offset
found = False
for instr in instr_list:
if instr['start'] == pass1_addr:
found = True
break
if found:
print(f" [✓] {label} — 0x{pass1_addr:x}")
else:
closest = None
for instr in instr_list:
if instr['start'] <= pass1_addr:
closest = instr
if closest:
real_addr = closest['start']
shift = real_addr - pass1_addr
if shift != 0:
errors.append(f"Метка '{label}': pass1=0x{pass1_addr:x}, pass2=0x{real_addr:x} (сдвиг {shift:+d} байт)")
print(f" [✗] {label} — pass1: 0x{pass1_addr:x}, pass2: 0x{real_addr:x} (сдвиг {shift:+d})")
else:
print(f" [✓] {label} — 0x{pass1_addr:x}")
else:
warnings.append(f"Метка '{label}' не найдена в CSV")
print(f" [?] {label} — не найдена в CSV")
print()
# Сравнение размеров инструкций
print("Проверка размеров инструкций:")
for instr in instr_list:
cmd = instr['cmd']
real_size = instr['size']
real_addr = instr['start']
mnemonic = cmd.split()[0] if cmd else ""
if mnemonic in FIXED_SIZE_INSTRUCTIONS:
pass1_size = FIXED_SIZE_INSTRUCTIONS[mnemonic]
elif mnemonic in ("загрузить", "сохранить", "загрузить_адрес"):
if 'MEM:reg_indirect:' in cmd:
pass1_size = 3
else:
pass1_size = 7
elif mnemonic in ("втолкнуть", "вытолкнуть"):
parts = cmd.split()
if len(parts) >= 2:
reg = parts[1]
if reg in ('р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'):
pass1_size = 2
else:
pass1_size = 1
else:
pass1_size = 1
elif mnemonic in ("прибавить_непосредственно", "вычесть_непосредственно", "сравнить_с"):
pass1_size = 7
elif mnemonic == "переместить_имм":
pass1_size = 10
elif mnemonic in ("переместить_сулями", "переместить_со_знаком"):
pass1_size = 8
elif mnemonic == "загрузить_байт":
pass1_size = 2
elif mnemonic == "втолкнуть_непосредственно":
pass1_size = 5
else:
instr_info = INSTRUCTIONS.get(mnemonic)
if instr_info and "opcode" in instr_info and instr_info["opcode"] is not None:
pass1_size = len(instr_info["opcode"])
else:
pass1_size = 3
status = "" if pass1_size == real_size else ""
if pass1_size != real_size:
diff = real_size - pass1_size
errors.append(f"Инструкция '{cmd}' на 0x{real_addr:x}: pass1={pass1_size}, pass2={real_size} (ошибка {diff:+d})")
print(f" [{status}] 0x{real_addr:x} {cmd} — pass1: {pass1_size}, pass2: {real_size}" +
(f" (ошибка {real_size - pass1_size:+d})" if pass1_size != real_size else ""))
print()
return errors, warnings
if __name__ == "__main__":
if ENABLE:
if len(sys.argv) != 3:
print("Использование: python kvs_verify.py <вход.проход1> <вход.csv>")
sys.exit(1)
pass1_file = sys.argv[1]
csv_file = sys.argv[2]
errors, warnings = verify(pass1_file, csv_file)
if warnings:
print(f"Предупреждений: {len(warnings)}")
for w in warnings:
print(f"{w}")
print()
if errors:
print(f"ОШИБОК: {len(errors)}")
for e in errors:
print(f"{e}")
print("\nСборка остановлена. Исправьте расхождения в размерах инструкций.")
sys.exit(1)
else:
print("Все размеры инструкций совпадают. Можно собирать.")
sys.exit(0)

View file

@ -0,0 +1,237 @@
#!/usr/bin/env python3
"""
Генератор CSV-таблицы для программы на КВС (функциональная версия)
Экспериментальный однопроходный ассемблер - с корректными заглушками ELF
"""
import sys
import csv
from typing import List, Optional, Tuple
# Глобальное состояние
entries = [] # Список записей: (address, byte, target, source, segment)
current_address = 0
current_segment = '.header'
last_segment = None
relocations = [] # Список отложенных ссылок: (pos, label, type, source)
def reset_state():
"""Сбросить состояние генератора"""
global entries, current_address, current_segment, last_segment, relocations
entries = []
current_address = 0
current_segment = '.header'
last_segment = None
relocations = []
def set_segment(segment: str):
"""Переключить текущий сегмент"""
global current_segment
current_segment = segment
def add_byte(value: int, source: str = "", target: Optional[int] = None):
"""Добавить один байт"""
global current_address, last_segment
# Показываем сегмент только при смене
show_segment = current_segment if current_segment != last_segment else None
if show_segment:
last_segment = current_segment
entries.append((
current_address,
value & 0xFF,
target,
source,
show_segment
))
current_address += 1
def add_bytes(values: List[int], source: str = ""):
"""Добавить последовательность байтов"""
for v in values:
add_byte(v, source)
def add_word32(value: int, source: str = ""):
"""Добавить 32-битное слово (little-endian)"""
add_bytes([
(value >> 0) & 0xFF,
(value >> 8) & 0xFF,
(value >> 16) & 0xFF,
(value >> 24) & 0xFF,
], source)
def add_word64(value: int, source: str = ""):
"""Добавить 64-битное слово (little-endian)"""
add_bytes([
(value >> 0) & 0xFF,
(value >> 8) & 0xFF,
(value >> 16) & 0xFF,
(value >> 24) & 0xFF,
(value >> 32) & 0xFF,
(value >> 40) & 0xFF,
(value >> 48) & 0xFF,
(value >> 56) & 0xFF,
], source)
def align_to(alignment: int):
"""Выровнять адрес до границы (просто двигаем адрес)"""
global current_address
padding = (alignment - (current_address % alignment)) % alignment
current_address += padding
def add_relocation(pos: int, label: str, reloc_type: str, source: str = ""):
"""Запомнить место для отложенной подстановки"""
relocations.append((pos, label, reloc_type, source))
def generate_elf_header():
"""Сгенерировать корректный ELF заголовок с заглушками"""
# EI_MAGIC
add_bytes([0x7F, 0x45, 0x4C, 0x46], "ELF magic")
# ei_class: 64-bit (2)
add_byte(2, "ELFCLASS64")
# ei_data: little-endian (1)
add_byte(1, "ELFDATA2LSB")
# ei_version: 1
add_byte(1, "ELF version")
# ei_osabi: System V (0)
add_byte(0, "OS ABI")
# ei_abiversion: 0
add_byte(0, "ABI version")
# ei_pad: 7 байт паддинга
add_bytes([0] * 7, "Padding")
# e_type: ET_EXEC (2)
add_word32(2, "e_type = ET_EXEC")
# e_machine: EM_X86_64 (62)
add_word32(62, "e_machine = EM_X86_64")
# e_version: 1
add_word32(1, "e_version")
# e_entry: точка входа (заглушка 0x401000)
add_word64(0x401000, "e_entry (stub: _start)")
# e_phoff: смещение до program headers (64 байта)
add_word64(64, "e_phoff")
# e_shoff: смещение до section headers (0 = нет секций)
add_word64(0, "e_shoff = 0")
# e_flags: 0
add_word32(0, "e_flags")
# e_ehsize: размер ELF заголовка (64)
add_word32(64, "e_ehsize")
# e_phentsize: размер program header entry (56)
add_word32(56, "e_phentsize")
# e_phnum: количество program headers (2)
add_word32(2, "e_phnum = 2")
# e_shentsize: размер section header entry (0)
add_word32(0, "e_shentsize = 0")
# e_shnum: количество section headers (0)
add_word32(0, "e_shnum = 0")
# e_shstrndx: индекс секции строк (0)
add_word32(0, "e_shstrndx")
def generate_program_headers():
"""Сгенерировать program headers с корректными выравниваниями"""
# Смещения в файле (должны быть кратны 4096)
text_offset = 0x1000 # 4096
data_offset = 0x2000 # 8192
# Program Header 1: TEXT (RX)
add_word32(1, "p_type = PT_LOAD")
add_word32(5, "p_flags = RX")
add_word64(text_offset, "p_offset (text)")
add_word64(0x401000, "p_vaddr (text)")
add_word64(0x401000, "p_paddr (text)")
add_word64(0, "p_filesz (stub)") # Заглушка
add_word64(0, "p_memsz (stub)") # Заглушка
add_word64(0x1000, "p_align (4KB)")
# Program Header 2: DATA (RW)
add_word32(1, "p_type = PT_LOAD")
add_word32(6, "p_flags = RW")
add_word64(data_offset, "p_offset (data)")
add_word64(0x402000, "p_vaddr (data)")
add_word64(0x402000, "p_paddr (data)")
add_word64(0, "p_filesz (stub)") # Заглушка
add_word64(0, "p_memsz (stub)") # Заглушка
add_word64(0x1000, "p_align (4KB)")
def generate_empty_program():
"""Сгенерировать пустую программу с корректным ELF скелетом"""
reset_state()
# Генерируем заголовки
set_segment('.header')
generate_elf_header()
generate_program_headers()
# Выравнивание до .text секции
align_to(0x1000)
# .text секция
set_segment('.text')
add_byte(0xCC, ".text section start (INT3)")
# Выравнивание до .data секции
align_to(0x1000)
# .data секция
set_segment('.data')
add_byte(0x00, ".data section start")
# Вывод информации
print(f"\n=== Сгенерирован скелет программы ===", file=sys.stderr)
print(f"ELF заголовок: 64 байта", file=sys.stderr)
print(f"Program headers: 112 байт (2 * 56)", file=sys.stderr)
print(f".text: 1 байт по адресу 0x401000", file=sys.stderr)
print(f".data: 1 байт по адресу 0x402000", file=sys.stderr)
print(f"\nПроверка readelf:", file=sys.stderr)
print(f" e_phoff = 64 (0x40) - верно", file=sys.stderr)
print(f" p_offset(text) = 4096 (0x1000) - кратно p_align", file=sys.stderr)
print(f" p_offset(data) = 8192 (0x2000) - кратно p_align", file=sys.stderr)
def save_to_csv(filename: str):
"""Сохранить таблицу в CSV"""
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f, delimiter=';')
writer.writerow(['адрес', 'байт', 'целевой_адрес', 'исходная_команда', 'сегмент'])
for addr, byte, target, source, segment in entries:
writer.writerow([
f"0x{addr:08x}",
f"0x{byte:02x}",
f"0x{target:08x}" if target is not None else "",
source,
segment if segment else ""
])
print(f"CSV сохранен: {filename}", file=sys.stderr)
def main():
if len(sys.argv) < 2:
print("Usage: python3 kvs_csv_builder.py <output.csv>")
sys.exit(1)
generate_empty_program()
save_to_csv(sys.argv[1])
print("\nГотово!", file=sys.stderr)
if __name__ == "__main__":
main()

View file

@ -1,136 +0,0 @@
## Исходник
```asm
.текст
.глобал _start
_start:
; ТЕСТ 1: Абсолютная адресация в .data
переместить_имм раикс, 0x42
сохранить [абсанные], раикс ; запись 0x42 по адресу абсанные (0x402000)
; ТЕСТ 2: Косвенная адресация в .data
переместить_имм рбикс, косв_данные ; рбикс = адрес косв_данные (0x402001)
переместить_имм раикс, 0x99
сохранить [рбикс], раикс ; запись 0x99 по адресу 0x402001
; ТЕСТ 3: Косвенная адресация в .бнд
переместить_имм рсикс, неиниц_бнд ; рсикс = адрес неиниц_бнд
переместить_имм раикс, 0x77
сохранить [рсикс], раикс ; запись 0x77 по адресу неиниц_бнд
; Читаем всё обратно
загрузить р8, [абсанные] ; чтение из 0x402000
загрузить р9, [рбикс] ; чтение из 0x402001
загрузить р10, [рсикс] ; чтение из неиниц_бнд
; ЗАВЕРШЕНИЕ: возвращаем значение из абсанные
загрузить рдиай, [абсанные] ; рдиай = значение из 0x402000
переместить_имм раикс, 60 ; номер системного вызова exit
вызов_системы
.данные
абсанные:
.байт 0
косв_данные:
.байт 0
.бнд
неиниц_бнд:
.резб 8
```
## Размещение секций в памяти
```
0x401000 ─ .text (код)
0x402000 ─ .data
├── абсанные (смещение 0): байт 0
└── косв_данные (смещение 1): байт 0
0x403000 ─ .бнд
└── неиниц_бнд (смещение 0): 8 байт, ноль
```
## Что подразумевается
1. **Тест 1** пишет `0x42` в `абсанные` по адресу `0x402000`.
2. **Тест 2** пишет `0x99` в `косв_данные` по адресу `0x402001`.
3. **Тест 3** пишет `0x77` в `неиниц_бнд` по адресу **`0x403000`**.
После этого:
- `[0x402000]` содержит `0x42`
- `[0x402001]` содержит `0x99`
- `[0x403000]` содержит `0x77`
Финал читает `[абсанные]` = `[0x402000]` = `0x42` в `рдиай` и завершается.
**Ожидаемый код возврата:** `66` (это `0x42`).
## Что происходит на самом деле
**Фактический код возврата:** `119` (это `0x77`).
## Причина
Инструкция `переместить_имм рсикс, неиниц_бнд` загружает в `рсикс` **неправильный адрес**. Вместо `0x403000` (адрес `.бнд`) регистр получает `0x402002` (адрес внутри `.data`).
Это происходит потому, что при вычислении адреса метки `неиниц_бнд` компилятор ошибочно использует базовый адрес секции `.data` (`0x402000`) вместо базового адреса секции `.бнд` (`0x403000`).
Смещение метки `неиниц_бнд` внутри `.бнд` равно `0`. Правильный расчёт должен быть: `0x403000 + 0 = 0x403000`. Но компилятор считает: `0x402000 + 0 = 0x402000`.
## Цепочка последствий
1. `рсикс` получает `0x402000` вместо `0x403000`.
2. `сохранить [рсикс], раикс` пишет `0x77` по адресу `0x402000` — **это ячейка `абсанные`**.
3. Значение `0x42`, записанное в Тесте 1, **затирается** значением `0x77`.
4. Финал читает `[абсанные]` и получает `0x77` вместо `0x42`.
5. Код возврата становится `119` вместо `66`.
## Как проверить
Если закомментировать Тест 3 (строки с `рсикс` и `неиниц_бнд`), код возврата станет `66` — баг исчезает, потому что `0x402000` не перезаписывается.
`vaddr_data` считается в **двух** местах:
### 1. `kvs_pass1.py` — метод `calculate_layout`
```python
vaddr_text = text_vaddr_base # 0x401000
vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE) # 0x402000
vaddr_bnd = align_up(vaddr_data + data_size, PAGE_SIZE) # 0x402000 или 0x403000
```
Эти значения записываются в pass1-файл как `PARAM:vaddr_text:...`, `PARAM:vaddr_data:...`, `PARAM:vaddr_bnd:...`.
### 2. `kvs_pass2.py` — конструктор `Pass2.__init__`
```python
self.vaddr_text = pass1_data["vaddr_text"] # читает из pass1
self.vaddr_data = align_up(self.vaddr_text + text_size, PAGE_SIZE) # вычисляет заново
```
**Pass2 не читает `vaddr_data` из pass1, а вычисляет сам.** А `vaddr_bnd` не читает и не вычисляет вообще.
### 3. `kvs_builder.py` — функция `create_elf`
```python
vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE) # вычисляет заново
vaddr_bnd = pass1_data.get("vaddr_bnd", ...) # читает из pass1
```
**Builder читает `vaddr_bnd` из pass1**, но энкодер (pass2) его не получает.
---
## Корень бага
| Модуль | `vaddr_data` | `vaddr_bnd` |
|--------|:-----------:|:----------:|
| pass1 | вычисляет ✅ | вычисляет ✅ |
| pass2 | вычисляет ✅ | **не читает** ❌ |
| builder | вычисляет ✅ | читает из pass1 ✅ |
| encoder (mutsize) | получает от pass2 ✅ | **не получает** ❌ |
Pass2 не передаёт `vaddr_bnd` в энкодер, поэтому `parse_operand` получает `vaddr_bnd=None` и подставляет `vaddr_data` для меток `.бнд`.

View file

@ -1,53 +0,0 @@
.текст
.глобал _start
_start:
; =============================================
; ТЕСТ 1: Абсолютная адресация в .data
; =============================================
переместить_имм раикс, 0x42
сохранить [абсанные], раикс
; =============================================
; ТЕСТ 2: Косвенная адресация в .data
; =============================================
переместить_имм рбикс, косв_данные
переместить_имм раикс, 0x99
сохранить [рбикс], раикс
; =============================================
; ТЕСТ 3: Косвенная адресация в .бнд
; =============================================
переместить_имм рсикс, неиниц_бнд
переместить_имм раикс, 0x77
сохранить [рсикс], раикс
; =============================================
; Читаем всё обратно и проверяем
; =============================================
; Читаем абсолютную из .data
загрузить р8, [абсанные]
; Читаем косвенную из .data
загрузить р9, [рбикс]
; Читаем косвенную из .бнд
загрузить р10, [рсикс]
; =============================================
; ЗАВЕРШЕНИЕ: возвращаем значение из абсолютной .data
; =============================================
загрузить рдиай, [абсанные]
переместить_имм раикс, 60
вызов_системы
.данные
абсанные:
.байт 0
косв_данные:
.байт 0
.бнд
неиниц_бнд:
.резб 8

View file

@ -1,67 +0,0 @@
.текст
.глобал _start
_start:
; Число для преобразования
переместить_имм раикс, 73
; Сохраняем число в .бнд
сохранить [число], раикс
; Загружаем обратно
загрузить раикс, [число]
; Делим на 10
переместить_имм рдикс, 0
переместить_имм рсикс, 10
разделить рсикс ; rax = 7 (частное), rdx = 3 (остаток)
; Сохраняем остаток в .бнд
сохранить [остаток], рдикс
; Частное (rax) — в цифру и выводим
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Загружаем остаток из .бнд
загрузить раикс, [остаток]
; Остаток — в цифру и выводим
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
буфер:
.байт 0, 0, 0, 0, 0, 0, 0, 0
nl:
.байт 0x0A
.бнд
число:
.резб 8
остаток:
.резб 8

View file

@ -1,80 +0,0 @@
.текст
.глобал _start
_start:
; Конвертируем 1034
переместить_имм раикс, 1034
; 1234 / 10 = 123, остаток 4
переместить_имм рдикс, 0
переместить_имм рсикс, 10
разделить рсикс
прибавить_непосредственно рдикс, 0x30
сохранить [цифра3], рдикс
; 123 / 10 = 12, остаток 3
переместить_имм рдикс, 0
разделить рсикс
прибавить_непосредственно рдикс, 0x30
сохранить [цифра2], рдикс
; 12 / 10 = 1, остаток 2
переместить_имм рдикс, 0
разделить рсикс
прибавить_непосредственно рдикс, 0x30
сохранить [цифра1], рдикс
; Частное 1 → последняя цифра
прибавить_непосредственно раикс, 0x30
сохранить [цифра0], раикс
; Выводим 4 цифры по одной
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра0
переместить_имм рдикс, 1
вызов_системы
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра1
переместить_имм рдикс, 1
вызов_системы
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра2
переместить_имм рдикс, 1
вызов_системы
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра3
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
nl:
.байт 0x0A
.бнд
цифра0:
.резб 8
цифра1:
.резб 8
цифра2:
.резб 8
цифра3:
.резб 8

View file

@ -1,94 +0,0 @@
.текст
.глобал _start
_start:
; МЕНЯЙ ЧИСЛО:
переместить_имм раикс, 57321
; 1-й разряд (единицы): число / 10
переместить_имм рдикс, 0
переместить_имм рсикс, 10
разделить рсикс ; rax = 5432, rdx = 1
прибавить_непосредственно рдикс, 0x30
сохранить [цифра4], рдикс
; 2-й разряд (десятки): частное / 10
переместить_имм рдикс, 0
разделить рсикс ; rax = 543, rdx = 2
прибавить_непосредственно рдикс, 0x30
сохранить [цифра3], рдикс
; 3-й разряд (сотни)
переместить_имм рдикс, 0
разделить рсикс ; rax = 54, rdx = 3
прибавить_непосредственно рдикс, 0x30
сохранить [цифра2], рдикс
; 4-й разряд (тысячи)
переместить_имм рдикс, 0
разделить рсикс ; rax = 5, rdx = 4
прибавить_непосредственно рдикс, 0x30
сохранить [цифра1], рдикс
; 5-й разряд (десятки тысяч)
прибавить_непосредственно раикс, 0x30
сохранить [цифра0], раикс
; Выводим 5 цифр по одной
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра0
переместить_имм рдикс, 1
вызов_системы
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра1
переместить_имм рдикс, 1
вызов_системы
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра2
переместить_имм рдикс, 1
вызов_системы
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра3
переместить_имм рдикс, 1
вызов_системы
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра4
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
nl:
.байт 0x0A
.бнд
цифра0:
.резб 8
цифра1:
.резб 8
цифра2:
.резб 8
цифра3:
.резб 8
цифра4:
.резб 8

View file

@ -1,94 +0,0 @@
.текст
.глобал _start
_start:
; МЕНЯЙ ЧИСЛО:
переместить_имм раикс, 59321
; 1-й разряд (единицы): число / 10
переместить_имм рдикс, 0
переместить_имм рсикс, 10
разделить рсикс ; rax = 5432, rdx = 1
прибавить_непосредственно рдикс, 0x30
сохранить [цифра4], рдикс
; 2-й разряд (десятки): частное / 10
переместить_имм рдикс, 0
разделить рсикс ; rax = 543, rdx = 2
прибавить_непосредственно рдикс, 0x30
сохранить [цифра3], рдикс
; 3-й разряд (сотни)
переместить_имм рдикс, 0
разделить рсикс ; rax = 54, rdx = 3
прибавить_непосредственно рдикс, 0x30
сохранить [цифра2], рдикс
; 4-й разряд (тысячи)
переместить_имм рдикс, 0
разделить рсикс ; rax = 5, rdx = 4
прибавить_непосредственно рдикс, 0x30
сохранить [цифра1], рдикс
; 5-й разряд (десятки тысяч)
прибавить_непосредственно раикс, 0x30
сохранить [цифра0], раикс
; Выводим 5 цифр по одной
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра0
переместить_имм рдикс, 1
вызов_системы
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра1
переместить_имм рдикс, 1
вызов_системы
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра2
переместить_имм рдикс, 1
вызов_системы
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра3
переместить_имм рдикс, 1
вызов_системы
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, цифра4
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
nl:
.байт 0x0A
.бнд
цифра0:
.резб 8
цифра1:
.резб 8
цифра2:
.резб 8
цифра3:
.резб 8
цифра4:
.резб 8

View file

@ -1,337 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Тестовый скрипт для проверки инструкций с фиксированной длиной
Запуск: python3 test_fixed_instructions.py [--keep-files]
"""
import sys
import os
import subprocess
import csv
# ANSI color codes
GREEN = '\033[92m'
RED = '\033[91m'
YELLOW = '\033[93m'
RESET = '\033[0m'
# === ТЕСТОВЫЙ ИСХОДНИК ===
TEST_SOURCE = '''.глобал _start
.текст
_start:
нет_операции
вызов_системы
вернуться
втолкнуть раикс
втолкнуть р8
вытолкнуть раикс
вытолкнуть р8
переместить раикс, рбикс
переместить р8, р9
сравнить раикс, рбикс
сравнить р8, р9
проверить раикс, рбикс
проверить р8, р9
прибавить раикс, рбикс
прибавить р8, р9
вычесть раикс, рбикс
вычесть р8, р9
и раикс, рбикс
и р8, р9
или раикс, рбикс
или р8, р9
исключающее_или раикс, рбикс
исключающее_или р8, р9
увеличить раикс
увеличить р8
увеличить еаикс
уменьшить раикс
уменьшить р8
уменьшить еаикс
инвертировать раикс
инвертировать еаикс
отрицать раикс
отрицать еаикс
переместить_имм раикс, 10
переместить_имм рбикс, 5
умножить рбикс
переместить_имм раикс, 100
переместить_имм рбикс, 7
разделить рбикс
умножить_знаковое рбикс
разделить_знаковое рбикс
сдвиг_влево раикс, 2
сдвиг_вправо раикс, 2
сдвиг_арифметический_вправо раикс, 2
вращать_влево раикс, 2
вращать_вправо раикс, 2
переход метка_длинная
короткий_переход меткаороткая
цикл меткаороткая
вызвать метка_длинная
метка_длинная:
нет_операции
нет_операции
нет_операции
меткаороткая:
нет_операции
переместить_имм раикс, 60
переместить_имм рдикс, 0
вызов_системы
'''
# === ОЖИДАЕМЫЕ РЕЗУЛЬТАТЫ ===
# Для инструкций с фиксированным кодом — полная проверка
EXPECTED_INSTRUCTIONS_FULL = {
"нет_операции": [0x90],
"вызов_системы": [0x0F, 0x05],
"вернуться": [0xC3],
"втолкнуть раикс": [0x50],
"втолкнуть р8": [0x41, 0x50],
"вытолкнуть раикс": [0x58],
"вытолкнуть р8": [0x41, 0x58],
"переместить раикс, рбикс": [0x48, 0x89, 0xD8],
"переместить р8, р9": [0x4D, 0x89, 0xC8],
"сравнить раикс, рбикс": [0x48, 0x39, 0xD8],
"сравнить р8, р9": [0x4D, 0x39, 0xC8],
"проверить раикс, рбикс": [0x48, 0x85, 0xD8],
"проверить р8, р9": [0x4D, 0x85, 0xC8],
"прибавить раикс, рбикс": [0x48, 0x01, 0xD8],
"прибавить р8, р9": [0x4D, 0x01, 0xC8],
"вычесть раикс, рбикс": [0x48, 0x29, 0xD8],
"вычесть р8, р9": [0x4D, 0x29, 0xC8],
"и раикс, рбикс": [0x48, 0x21, 0xD8],
"и р8, р9": [0x4D, 0x21, 0xC8],
"или раикс, рбикс": [0x48, 0x09, 0xD8],
"или р8, р9": [0x4D, 0x09, 0xC8],
"исключающее_или раикс, рбикс": [0x48, 0x31, 0xD8],
"исключающее_или р8, р9": [0x4D, 0x31, 0xC8],
"увеличить раикс": [0x48, 0xFF, 0xC0],
"увеличить р8": [0x49, 0xFF, 0xC0],
"увеличить еаикс": [0xFF, 0xC0],
"уменьшить раикс": [0x48, 0xFF, 0xC8],
"уменьшить р8": [0x49, 0xFF, 0xC8],
"уменьшить еаикс": [0xFF, 0xC8],
"инвертировать раикс": [0x48, 0xF7, 0xD0],
"инвертировать еаикс": [0xF7, 0xD0],
"отрицать раикс": [0x48, 0xF7, 0xD8],
"отрицать еаикс": [0xF7, 0xD8],
"умножить рбикс": [0x48, 0xF7, 0xE0],
"разделить рбикс": [0x48, 0xF7, 0xF0],
"умножить_знаковое рбикс": [0x48, 0xF7, 0xE8],
"разделить_знаковое рбикс": [0x48, 0xF7, 0xF8],
"сдвиг_влево раикс, 2": [0x48, 0xC1, 0xE0, 0x02],
"сдвиг_вправо раикс, 2": [0x48, 0xC1, 0xE8, 0x02],
"сдвиг_арифметический_вправо раикс, 2": [0x48, 0xC1, 0xF8, 0x02],
"вращать_влево раикс, 2": [0x48, 0xC1, 0xC0, 0x02],
"вращать_вправо раикс, 2": [0x48, 0xC1, 0xC8, 0x02],
"переместить_имм раикс, 10": [0x48, 0xB8, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
"переместить_имм рбикс, 5": [0x48, 0xBB, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
"переместить_имм раикс, 100": [0x48, 0xB8, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
"переместить_имм рбикс, 7": [0x48, 0xBB, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
"переместить_имм раикс, 60": [0x48, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
"переместить_имм рдикс, 0": [0x48, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
}
# Инструкции, у которых проверяем только opcode (первые байты)
EXPECTED_INSTRUCTIONS_PREFIX = {
"переход метка_длинная": [0xE9], # JMP rel32
"короткий_переход меткаороткая": [0xEB], # JMP SHORT
"цикл меткаороткая": [0xE2], # LOOP
"вызвать метка_длинная": [0xE8], # CALL rel32
}
def read_csv_instructions(csv_file):
"""Читает CSV и возвращает словарь {мнемоника: [байты]}"""
instructions = {}
current_mnemonic = None
current_bytes = []
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.reader(f, delimiter=';')
header = next(reader)
for row in reader:
if len(row) < 4:
continue
cmd = row[3].strip()
byte_str = row[1].strip()
if not byte_str:
continue
byte_val = int(byte_str, 16)
if cmd:
if current_mnemonic and current_bytes:
instructions[current_mnemonic] = current_bytes
current_mnemonic = cmd
current_bytes = [byte_val]
else:
if current_mnemonic:
current_bytes.append(byte_val)
if current_mnemonic and current_bytes:
instructions[current_mnemonic] = current_bytes
return instructions
def run_tests(generated_instructions):
"""Сравнивает сгенерированные инструкции с ожидаемыми"""
errors = []
missing = []
# Проверяем инструкции с полным совпадением
for mnemonic, expected_bytes in EXPECTED_INSTRUCTIONS_FULL.items():
if mnemonic not in generated_instructions:
missing.append(mnemonic)
continue
actual_bytes = generated_instructions[mnemonic]
if actual_bytes != expected_bytes:
expected_hex = ' '.join(f'{b:02X}' for b in expected_bytes)
actual_hex = ' '.join(f'{b:02X}' for b in actual_bytes)
errors.append(f" {mnemonic}: ожидалось [{expected_hex}], получено [{actual_hex}]")
# Проверяем инструкции только по префиксу
for mnemonic, expected_prefix in EXPECTED_INSTRUCTIONS_PREFIX.items():
if mnemonic not in generated_instructions:
missing.append(mnemonic)
continue
actual_bytes = generated_instructions[mnemonic]
prefix_len = len(expected_prefix)
if len(actual_bytes) < prefix_len:
errors.append(f" {mnemonic}: слишком короткая ({len(actual_bytes)} байт, ожидалось минимум {prefix_len})")
elif actual_bytes[:prefix_len] != expected_prefix:
expected_hex = ' '.join(f'{b:02X}' for b in expected_prefix)
actual_hex = ' '.join(f'{b:02X}' for b in actual_bytes[:prefix_len])
errors.append(f" {mnemonic}: префикс [{expected_hex}...], получено [{actual_hex}...]")
return errors, missing
def cleanup(files_to_delete, keep_files=False):
"""Удаляет временные файлы"""
if keep_files:
print("\nФлаг --keep-files указан, промежуточные файлы сохранены:")
for f in files_to_delete:
if os.path.exists(f):
print(f" {f}")
return
deleted = []
for f in files_to_delete:
if os.path.exists(f):
os.remove(f)
deleted.append(f)
if deleted:
print(f"\nУдалено {len(deleted)} временных файлов")
def main():
keep_files = '--keep-files' in sys.argv or '-k' in sys.argv
base_name = "т1"
source_file = f"{base_name}.квс"
tokens_file = f"{base_name}.токены"
ast_file = f"{base_name}.аст"
p1_file = f"{base_name}.проход1"
csv_file = f"{base_name}.csv"
elf_file = f"{base_name}.elf"
temp_files = [tokens_file, ast_file, p1_file, csv_file, elf_file]
print("КВС Тестировщик - Инструкции с фиксированной длиной\n")
print("=" * 60)
# Шаг 1: Создание исходного файла
print("Шаг 1: Создание тестового исходника...")
with open(source_file, 'w', encoding='utf-8') as f:
f.write(TEST_SOURCE)
print(f" Создан {source_file}")
# Шаг 2: Компиляция
print("\nШаг 2: Компиляция...")
result = subprocess.run(
[sys.executable, "kvs_build.py", source_file],
capture_output=True,
text=True
)
if result.returncode != 0:
print(" ОШИБКА компиляции:")
print(result.stderr)
print("\nОставшиеся файлы для отладки:")
print(f" {source_file}")
if os.path.exists(csv_file):
print(f" {csv_file}")
sys.exit(1)
print(" Компиляция успешна")
# Шаг 3: Проверка результатов
print("\nШаг 3: Проверка сгенерированного кода...")
if not os.path.exists(csv_file):
print(f" Файл {csv_file} не найден!")
sys.exit(1)
generated_instructions = read_csv_instructions(csv_file)
errors, missing = run_tests(generated_instructions)
# Вывод результатов
print("\n" + "=" * 60)
print("РЕЗУЛЬТАТЫ ТЕСТИРОВАНИЯ:")
print("=" * 60)
if missing:
print(f"\n{YELLOW}ОТСУТСТВУЮТ ИНСТРУКЦИИ ({len(missing)}):{RESET}")
for m in missing[:10]:
print(f" - {m}")
if len(missing) > 10:
print(f" ... и ещё {len(missing)-10}")
if errors:
print(f"\n{RED}НАЙДЕНО {len(errors)} ОШИБОК В КОДЕ:{RESET}")
for err in errors:
print(err)
success = False
else:
print(f"\n{GREEN}НЕТ ОШИБОК! ВСЕ ИНСТРУКЦИИ ЗАКОДИРОВАНЫ ВЕРНО!{RESET}")
success = True
# Статистика
print(f"\nСтатистика:")
print(f" Ожидалось инструкций (полная проверка): {len(EXPECTED_INSTRUCTIONS_FULL)}")
print(f" Ожидалось инструкций (проверка префикса): {len(EXPECTED_INSTRUCTIONS_PREFIX)}")
print(f" Сгенерировано инструкций: {len(generated_instructions)}")
# Шаг 4: Очистка
cleanup([source_file] + temp_files, keep_files)
# Финальный вердикт
print("\n" + "=" * 60)
if success:
print(f"{GREEN}ТЕСТЫ ПРОЙДЕНЫ УСПЕШНО!{RESET}")
sys.exit(0)
else:
print(f"{RED}ТЕСТЫ НЕ ПРОЙДЕНЫ!{RESET}")
sys.exit(1)
if __name__ == "__main__":
main()

View file

@ -1,9 +0,0 @@
.текст
.глобал _start
_start:
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.бнд
буфер: .резб 1048576 ; 1 МБ = 1024 * 1024

View file

@ -1,45 +0,0 @@
.текст
.глобал _start
_start:
; =============================================
; ТЕСТ 1: Абсолютная адресация в .бнд
; =============================================
переместить_имм раикс, 0x42
сохранить [абс_перем], раикс
; =============================================
; ТЕСТ 2: Косвенная адресация в .бнд
; =============================================
переместить_имм рбикс, косв_перем
переместить_имм раикс, 0x99
сохранить [рбикс], раикс
; =============================================
; ТЕСТ 3: Ещё одна косвенная адресация в .бнд
; =============================================
переместить_имм рсикс, ещё_перем
переместить_имм раикс, 0x77
сохранить [рсикс], раикс
; =============================================
; Читаем всё обратно
; =============================================
загрузить р8, [абс_перем]
загрузить р9, [рбикс]
загрузить р10, [рсикс]
; =============================================
; ЗАВЕРШЕНИЕ: возвращаем из абс_перем
; =============================================
загрузить рдиай, [абс_перем]
переместить_имм раикс, 60
вызов_системы
.бнд
абс_перем:
.резб 1
косв_перем:
.резб 1
ещё_перем:
.резб 8

View file

@ -1,15 +0,0 @@
.текст
.глобал _start
_start:
; Запись значения 42 в переменную по метке
переместить_имм раикс, 42
сохранить [переменная], раикс
; Завершение с кодом 42
переместить_имм раикс, 60
загрузить рдиай, [переменная]
вызов_системы
.данные
переменная: .байт 0

View file

@ -1,15 +0,0 @@
.текст
.глобал _start
_start:
; Запись значения 42 в переменную по адресу 0x402000
переместить_имм раикс, 42
сохранить [0x402000], раикс
; Завершение с кодом 42 (читаем из переменной)
переместить_имм раикс, 60
загрузить рдиай, [0x402000]
вызов_системы
.данные
тестовая_переменная: .байт 0

View file

@ -1,34 +0,0 @@
.текст
.глобал _start
_start:
; === ТЕСТ 1: Запись через косвенную адресацию ===
; Загружаем адрес переменной в регистр
переместить_имм рбикс, тестовая_переменная
; Записываем 42 через косвенную адресацию [рбикс]
переместить_имм раикс, 42
сохранить [рбикс], раикс
; === ТЕСТ 2: Чтение через косвенную адресацию ===
; Загружаем адрес другой переменной в регистр
переместить_имм рсикс, вторая_переменная
; Читаем через косвенную адресацию [рсикс]
загрузить рдикс, [рсикс]
; === ТЕСТ 3: Проверяем, что записалось ===
; Читаем первую переменную через косвенную
загрузить рсикс, [рбикс]
; === ЗАВЕРШЕНИЕ ===
; Выходим с кодом из первой переменной (должно быть 42)
переместить_имм раикс, 60
переместить рдиай, рсикс
вызов_системы
.данные
тестовая_переменная:
.байт 0
вторая_переменная:
.байт 99

View file

@ -1,50 +0,0 @@
.текст
.глобал _start
_start:
; =============================================
; ТЕСТ 1: Абсолютная адресация
; =============================================
переместить_имм раикс, 0x42
сохранить [абсанные], раикс
; =============================================
; ТЕСТ 2: Косвенная адресация
; =============================================
переместить_имм рбикс, косв_данные
переместить_имм раикс, 0x99
сохранить [рбикс], раикс
; =============================================
; ТЕСТ 3: Ещё одна косвенная адресация
; =============================================
переместить_имм рсикс, ещё_данные
переместить_имм раикс, 0x77
сохранить [рсикс], раикс
; =============================================
; Читаем всё обратно
; =============================================
загрузить р8, [абсанные]
загрузить р9, [рбикс]
загрузить р10, [рсикс]
; =============================================
; ЗАВЕРШЕНИЕ: возвращаем из абсолютной переменной
; =============================================
загрузить рдиай, [абсанные]
переместить_имм раикс, 60
вызов_системы
.данные
абсанные:
.байт 0
косв_данные:
.байт 0
ещё_данные:
.байт 0, 0, 0, 0, 0, 0, 0, 0
.бнд
буфер: .резб 1048576 ; 1 МБ = 1024 * 1024
переменная: .резкс 1 ; 8 байт под длину
буфер_строки: .резкс 1 ; 8 байт под указатель на строку

View file

@ -1,28 +0,0 @@
.текст
.глобал _start
_start:
; 25 - длина сообщения из метки msg
; Запись значения 25 в переменную по метке
переместить_имм рдикс, 25
сохранить [переменная], рдикс
; перепишем для теста
переместить_имм рдикс, 0
; Системный вызов write(1, msg, len)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg
загрузить рдикс, [переменная]
вызов_системы
; Системный вызов exit()
переместить_имм раикс, 60 ; номер syscall exit = 60
переместить_имм рдиай, 44 ; код возврата (старый метод)
вызов_системы
.данные
msg: .строка "Тест пройден!\n" ; не менять их местами, чтоб не затереть текст
переменная: .байт 0 ; тут либо резервировать пустые, либо .bss изобретать (или кучу?)

View file

@ -1,30 +0,0 @@
.текст
.глобал _start
_start:
; 25 - длина сообщения из метки msg
; Запись значения 25 в переменную по метке
переместить_имм рдикс, 25
сохранить [переменная], рдикс
; перепишем для теста
переместить_имм рдикс, 0
; Системный вызов write(1, msg, len)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg
загрузить рдикс, [переменная]
вызов_системы
; Системный вызов exit()
переместить_имм раикс, 60 ; номер syscall exit = 60
переместить_имм рдиай, 44 ; код возврата (старый метод)
вызов_системы
.данные
msg: .строка "Тест пройден!\n" ; строка остаётся в .данные
.бнд
переменная: .резкс 1 ; 8 байт под qword (как и было .байт 0)

View file

@ -1,36 +0,0 @@
.текст
.глобал _start
_start:
; 25 - длина сообщения из метки msg
; Запись значения 25 в переменную в .бнд
переместить_имм рдикс, 25
сохранить [переменная], рдикс
; Загружаем адрес строки и сохраняем в буфер в .бнд
загрузить_адрес раикс, [msg]
сохранить [буфер_строки], раикс
; перепишем для теста
переместить_имм рдикс, 0
; Системный вызов write(1, msg, len)
переместить_имм раикс, 1
переместить_имм рдиай, 1
загрузить рсиай, [буфер_строки]
загрузить рдикс, [переменная]
вызов_системы
; Системный вызов exit()
переместить_имм раикс, 60
переместить_имм рдиай, 44
вызов_системы
.данные
msg: .строка "Тест пройден!\n"
.бнд
переменная: .резкс 1 ; 8 байт под длину
буфер_строки: .резкс 1 ; 8 байт под указатель на строку

View file

@ -1,835 +0,0 @@
; длин_тест9.квс
; Тест: запутанные переходы, крякмис (для длинных переходов)
.текст
.глобал _start
_start:
; Инициализация регистров
переместить_имм раикс, 10 ; rax = 10
переместить_имм рбикс, 5 ; rbx = 5
переместить_имм рсикс, 10 ; rcx = 10 (для проверки ZF в jz)
; ПЕРВЫЙ ПЕРЕХОД: переход_если_неоль
; ZF=0 (так как rax=10), значит jnz сработает
; Прыгаем к метке 'проверка_2', пропуская мертвый_код_1
переход_если_неоль проверка_2
; --- МЕРТВЫЙ КОД 1 ---
; Этот код НЕ должен выполниться
; Добавляем "мусор", чтобы точно выйти за пределы короткого перехода
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 2
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
; ---------------------
проверка_2:
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 1: "Два шага вперед" - переход через мертвый_код_2 и мертвый_код_3
; Прыгаем к проверка_4, минуя мертвый_код_2 и мертвый_код_3
переход проверка_4
; --- МЕРТВЫЙ КОД 2 ---
; Этот код НЕ должен выполниться из-за прыжка выше
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 2
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
; ---------------------
мертвый_код_3:
; ЖИВОЙ КОД 3: Этот код выполнится благодаря прыжку "назад"
; Выведем сообщение, чтобы убедиться, что он выполнился
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_live_from_3
переместить_имм рдикс, len_msg_live_from_3
вызов_системы
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 3: "Четыре вперед" - переход через мертвый_код_4, 5, 6, 7
; Цель слишком далеко для короткого перехода. Используем длинный.
; Прыгаем к проверка_8
переход проверка_8
; ---------------------
проверка_4:
; ЧЕТВЁРТЫЙ ПЕРЕХОД: переход_если_больше
; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0
сравнить раикс, рбикс
; Условие jg: ZF=0 (истина) И SF=OF (0=0, истина). jg СРАБОТАЕТ.
; Мы хотим прыгнуть МИМО мертвого кода 4, если jg сработает (т.е. если rax > rbx).
переход_если_больше мимоертвогоода_4
; --- МЕРТВЫЙ КОД 4 ---
; Этот код НЕ должен выполниться (так как jg сработал)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 2
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
; ---------------------
мимоертвогоода_4:
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 2: "Один назад" - переход к мертвомуоду_3 (делая его живым)
переход мертвый_код_3
; --- МЕРТВЫЙ КОД 5 ---
; Этот код НЕ должен выполниться
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 2
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
; ---------------------
; --- МЕРТВЫЙ КОД 6 ---
; Этот код НЕ должен выполниться
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 2
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
; ---------------------
; --- МЕРТВЫЙ КОД 7 ---
; Этот код НЕ должен выполниться
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 2
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
; ---------------------
проверка_8:
; СЕДЬМОЙ ПЕРЕХОД: переход_если_перенос
; Выполним вычитание, которое вызовет перенос: rbx - rax = 5 - 10
переместить_имм рбикс, 5 ; rbx = 5
переместить_имм раикс, 10 ; rax = 10
; rbx - rax = 5 - 10 -> CF=1
вычесть рбикс, раикс ; rbx = rbx - rax = 5 - 10. Это вызовет перенос (CF=1).
; Условие jc: CF=1. CF=1. jc СРАБОТАЕТ.
; Мы хотим прыгнуть МИМО мертвого кода 8, если jc сработает (т.е. если был перенос).
переход_если_перенос мимоертвогоода_8
; --- МЕРТВЫЙ КОД 8 ---
; Этот код НЕ должен выполниться (так как jc сработал)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 2
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
; ---------------------
мимоертвогоода_8:
; ВОСЬМОЙ ПЕРЕХОД: переход_если_нет_переноса
; Убедимся, что CF=0. Выполним операцию, которая сбросит CF.
сравнить раикс, раикс ; CF = 0 (так как rax - rax = 0, без переноса)
; Условие jnc: CF=0. CF=0. jnc СРАБОТАЕТ.
; Мы хотим прыгнуть МИМО мертвого кода 9, если jnc сработает (т.е. если НЕ было переноса).
переход_если_нет_переноса мимоертвогоода_9
; --- МЕРТВЫЙ КОД 9 ---
; Этот код НЕ должен выполниться (так как jnc сработал)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 2
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
; ---------------------
мимоертвогоода_9:
; ДЕВЯТЫЙ ПЕРЕХОД: переход (безусловный)
; Просто прыгаем мимо мертвого кода 10.
переход мимоертвогоода_10
; --- МЕРТВЫЙ КОД 10 ---
; Этот код НЕ должен выполниться (так как jmp сработал)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 2
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
; ---------------------
мимоертвогоода_10:
; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ ---
вывести_сообщение:
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_success
переместить_имм рдикс, len_msg_success
вызов_системы
; --- ЗАВЕРШЕНИЕ ---
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
; Перемешиваем строки и константы
; "Живой из 3!\n" = 8 букв * 2 + 1 (!) + 1 (\n от .строкауль) = 16 + 2 = 18 байт на содержимое. len = 18
msg_live_from_3: .строкауль "Живой из 3!\n"
.константа len_msg_live_from_3 = 18
; "Успех!\n" = 5 букв * 2 + 1 (!) + 1 (\n от .строкауль) = 10 + 2 = 12 байт на содержимое. len = 12
msg_success: .строкауль "Успех!\n"
.константа len_msg_success = 12
; "Мертвый код 10!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строкауль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_10: .строкауль "Мертвый код 10!"
.константа len_msg_dead_10 = 19
; "Мертвый код 9!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строкауль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_9: .строкауль "Мертвый код 9!"
.константа len_msg_dead_9 = 19
; "Мертвый код 8!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строкауль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_8: .строкауль "Мертвый код 8!"
.константа len_msg_dead_8 = 19
; "Мертвый код 7!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строкауль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_7: .строкауль "Мертвый код 7!"
.константа len_msg_dead_7 = 19
; "Мертвый код 6!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строкауль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_6: .строкауль "Мертвый код 6!"
.константа len_msg_dead_6 = 19
; "Мертвый код 5!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строкауль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_5: .строкауль "Мертвый код 5!"
.константа len_msg_dead_5 = 19
; "Мертвый код 4!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строкауль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_4: .строкауль "Мертвый код 4!"
.константа len_msg_dead_4 = 19
; "Мертвый код 3!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строкауль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_3: .строкауль "Мертвый код 3!"
.константа len_msg_dead_3 = 19
; "Мертвый код 2!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строкауль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_2: .строкауль "Мертвый код 2!"
.константа len_msg_dead_2 = 19
; "Мертвый код 1!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строкауль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_1: .строкауль "Мертвый код 1!"
.константа len_msg_dead_1 = 19

View file

@ -1,73 +0,0 @@
.текст
.глобал _start
_start:
; Тест: длина числа 1234
переместить_имм раикс, 1234
вызвать длина_числа ; rax = количество цифр
; Выводим результат как цифру
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
; =============================================
; длина_числа: количество десятичных цифр в rax
; Вход: rax = число
; Выход: rax = количество цифр (1..20)
; =============================================
длина_числа:
втолкнуть р8
втолкнуть р9
переместить р8, раикс ; р8 = число
переместить_имм р9, 0 ; счётчик = 0
; Проверка на 0
сравнить_с р8, 0
короткий_переход_если_неравно длина_цикл
переместить_имм раикс, 1 ; 0 — это 1 цифра
вытолкнуть р9
вытолкнуть р8
вернуться
длина_цикл:
увеличить р9 ; счётчик++
; Делим на 10
переместить раикс, р8
переместить_имм рдикс, 0
переместить_имм рсикс, 10
разделить рсикс
переместить р8, раикс ; частное
сравнить_с р8, 0
короткий_переход_если_неравно длина_цикл
переместить раикс, р9 ; результат
вытолкнуть р9
вытолкнуть р8
вернуться
.данные
буфер:
.байт 0, 0, 0, 0, 0, 0, 0, 0
nl:
.байт 0x0A

View file

@ -1,104 +0,0 @@
00000000 7F45 jg 0x47
00000002 4C rex.wr
00000003 460201 add r8b,[rcx]
00000006 0100 add [rax],eax
00000010 0200 add al,[rax]
00000012 3E0001 add [ds:rcx],al
00000019 104000 adc [rax+0x0],al
00000027 005020 add [rax+0x20],dl
00000034 400038 add [rax],dil
00000037 0003 add [rbx],al
00000039 004000 add [rax+0x0],al
0000003C 0500040001 add eax,0x1000400
00000043 000400 add [rax+rax],al
00000059 004000 add [rax+0x0],al
00000060 E800000000 call 0x65
00000069 1000 adc [rax],al
00000071 1000 adc [rax],al
00000077 0001 add [rcx],al
0000007B 000500000000 add [rel 0x81],al
00000081 1000 adc [rax],al
00000089 104000 adc [rax+0x0],al
00000090 0010 add [rax],dl
00000097 004000 add [rax+0x0],al
000000A0 0010 add [rax],dl
000000A8 0010 add [rax],dl
000000B0 0100 add [rax],eax
000000B4 06 db 0x06
000000B9 2000 and [rax],al
000000C1 204000 and [rax+0x0],al
000000C8 0020 add [rax],ah
000000CF 001500000000 add [rel 0xd5],dl
000000D9 1000 adc [rax],al
000000E1 1000 adc [rax],al
00000FFF 0048B8 add [rax-0x48],cl
00001002 0100 add [rax],eax
0000100A 48BF010000000000 mov rdi,0x1
-0000
00001014 48BE002040000000 mov rsi,0x402000
-0000
0000101E 48BA150000000000 mov rdx,0x15
-0000
00001028 0F05 syscall
0000102A 48B83C0000000000 mov rax,0x3c
-0000
00001034 48BF000000000000 mov rdi,0x0
-0000
0000103E 0F05 syscall
00002000 D09FD180D0B8 rcr byte [rdi-0x472f7f2f],1
00002006 D0 db 0xd0
00002007 B2D0 mov dl,0xd0
00002009 B5D1 mov ch,0xd1
0000200B 82 db 0x82
0000200C 20D0 and al,dl
0000200E BCD0B8D180 mov esp,0x80d1b8d0
00002013 210A and [rdx],ecx
00002015 D0A1D0B1D0BE shl byte [rcx-0x412f4e30],1
0000201B D180D189D0B8 rol dword [rax-0x472f762f],1
00002021 D0BA20D09AD0 sar byte [rdx-0x2f652fe0],1
00002027 92 xchg eax,edx
00002028 D0A100000000 shl byte [rcx+0x0],1
00002030 002E add [rsi],ch
00002032 7465 jz 0x2099
00002034 7874 js 0x20aa
00002036 002E add [rsi],ch
00002038 64 fs
00002039 61 db 0x61
0000203A 7461 jz 0x209d
0000203C 002E add [rsi],ch
0000203E 63 db 0x63
0000203F 6F outsd
00002040 6D insd
00002041 6D insd
00002042 656E gs outsb
00002044 7400 jz 0x2046
00002046 2E7368 cs jnc 0x20b1
00002049 7374 jnc 0x20bf
0000204B 7274 jc 0x20c1
0000204D 61 db 0x61
0000204E 62 db 0x62
0000207F 0001 add [rcx],al
0000208F 0001 add [rcx],al
00002093 0001 add [rcx],al
00002097 0006 add [rsi],al
000020A1 104000 adc [rax+0x0],al
000020A8 0010 add [rax],dl
000020BF 0010 add [rax],dl
000020CF 0007 add [rdi],al
000020D3 0001 add [rcx],al
000020D7 0003 add [rbx],al
000020E1 204000 and [rax+0x0],al
000020E8 0020 add [rax],ah
000020F0 1500000000 adc eax,0x0
000020FF 0008 add [rax],cl
0000210F 000D00000001 add [rel 0x1002115],cl
00002127 001520000000 add [rel 0x214d],dl
0000212F 0016 add [rsi],dl
0000213F 0001 add [rcx],al
0000214F 0016 add [rsi],dl
00002153 0003 add [rbx],al
00002167 0030 add [rax],dh
00002169 2000 and [rax],al
0000216F 0020 add [rax],ah
0000217F 0001 add [rcx],al
0000218F 00 db 0x00

View file

@ -1,204 +0,0 @@
; сложный_тест9.квс
; Тест: запутанные переходы, крякмис
.текст
.глобал _start
_start:
; Инициализация регистров
переместить_имм раикс, 10 ; rax = 10
переместить_имм рбикс, 5 ; rbx = 5
переместить_имм рсикс, 10 ; rcx = 10 (для проверки ZF в jz)
; ПЕРВЫЙ ПЕРЕХОД: короткий_переход_если_неоль
; ZF=0 (так как rax=10), значит jnz сработает
; Прыгаем к метке 'проверка_2', пропуская мертвый_код_1
короткий_переход_если_неоль проверка_2
; --- МЕРТВЫЙ КОД 1 ---
; Этот код НЕ должен выполниться
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
; ---------------------
проверка_2:
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 1: "Два шага вперед" - короткий_переход через мертвый_код_2 и мертвый_код_3
; Прыгаем к проверка_4, минуя мертвый_код_2 и мертвый_код_3
короткий_переход проверка_4
; --- МЕРТВЫЙ КОД 2 ---
; Этот код НЕ должен выполниться из-за прыжка выше
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
; ---------------------
мертвый_код_3:
; ЖИВОЙ КОД 3: Этот код выполнится благодаря прыжку "назад"
; Выведем сообщение, чтобы убедиться, что он выполнился
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_live_from_3
переместить_имм рдикс, len_msg_live_from_3
вызов_системы
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 3: "Четыре вперед" - переход через мертвый_код_4, 5, 6, 7
; Цель слишком далеко для короткого перехода. Используем длинный.
; Прыгаем к проверка_8
переход проверка_8
; ---------------------
проверка_4:
; ЧЕТВЁРТЫЙ ПЕРЕХОД: короткий_переход_если_больше
; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0
сравнить раикс, рбикс
; Условие jg: ZF=0 (истина) И SF=OF (0=0, истина). jg СРАБОТАЕТ.
; Мы хотим прыгнуть МИМО мертвого кода 4, если jg сработает (т.е. если rax > rbx).
короткий_переход_если_больше мимоертвогоода_4
; --- МЕРТВЫЙ КОД 4 ---
; Этот код НЕ должен выполниться (так как jg сработал)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_4
переместить_имм рдикс, len_msg_dead_4
вызов_системы
; ---------------------
мимоертвогоода_4:
; ДОПОЛНИТЕЛЬНЫЙ ПЕРЕХОД 2: "Один назад" - короткий_переход к мертвомуоду_3 (делая его живым)
короткий_переход мертвый_код_3
; --- МЕРТВЫЙ КОД 5 ---
; Этот код НЕ должен выполниться
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_5
переместить_имм рдикс, len_msg_dead_5
вызов_системы
; ---------------------
; --- МЕРТВЫЙ КОД 6 ---
; Этот код НЕ должен выполниться
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_6
переместить_имм рдикс, len_msg_dead_6
вызов_системы
; ---------------------
; --- МЕРТВЫЙ КОД 7 ---
; Этот код НЕ должен выполниться
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_7
переместить_имм рдикс, len_msg_dead_7
вызов_системы
; ---------------------
проверка_8:
; СЕДЬМОЙ ПЕРЕХОД: короткий_переход_если_перенос
; Выполним вычитание, которое вызовет перенос: rbx - rax = 5 - 10
переместить_имм рбикс, 5 ; rbx = 5
переместить_имм раикс, 10 ; rax = 10
; rbx - rax = 5 - 10 -> CF=1
вычесть рбикс, раикс ; rbx = rbx - rax = 5 - 10. Это вызовет перенос (CF=1).
; Условие jc: CF=1. CF=1. jc СРАБОТАЕТ.
; Мы хотим прыгнуть МИМО мертвого кода 8, если jc сработает (т.е. если был перенос).
короткий_переход_если_перенос мимоертвогоода_8
; --- МЕРТВЫЙ КОД 8 ---
; Этот код НЕ должен выполниться (так как jc сработал)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_8
переместить_имм рдикс, len_msg_dead_8
вызов_системы
; ---------------------
мимоертвогоода_8:
; ВОСЬМОЙ ПЕРЕХОД: короткий_переход_если_нет_переноса
; Убедимся, что CF=0. Выполним операцию, которая сбросит CF.
сравнить раикс, раикс ; CF = 0 (так как rax - rax = 0, без переноса)
; Условие jnc: CF=0. CF=0. jnc СРАБОТАЕТ.
; Мы хотим прыгнуть МИМО мертвого кода 9, если jnc сработает (т.е. если НЕ было переноса).
короткий_переход_если_нет_переноса мимоертвогоода_9
; --- МЕРТВЫЙ КОД 9 ---
; Этот код НЕ должен выполниться (так как jnc сработал)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_9
переместить_имм рдикс, len_msg_dead_9
вызов_системы
; ---------------------
мимоертвогоода_9:
; ДЕВЯТЫЙ ПЕРЕХОД: короткий_переход (безусловный)
; Просто прыгаем мимо мертвого кода 10.
короткий_переход мимоертвогоода_10
; --- МЕРТВЫЙ КОД 10 ---
; Этот код НЕ должен выполниться (так как jmp сработал)
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_10
переместить_имм рдикс, len_msg_dead_10
вызов_системы
; ---------------------
мимоертвогоода_10:
; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ ---
вывести_сообщение:
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_success
переместить_имм рдикс, len_msg_success
вызов_системы
; --- ЗАВЕРШЕНИЕ ---
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
; Перемешиваем строки и константы
; "Живой из 3!\n" = 8 букв * 2 + 1 (!) + 2 (\n) = 16 + 3 = 19 байт на содержимое. len = 19
msg_live_from_3: .строкауль "Живой из 3!\n"
.константа len_msg_live_from_3 = 19
; "Успех!\n" = 5 букв * 2 + 1 (!) + 2 (\n) = 13 байт на содержимое. len = 13
msg_success: .строкауль "Успех!\n"
.константа len_msg_success = 13
; "Мертвый код 10!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
msg_dead_10: .строкауль "Мертвый код 10!"
.константа len_msg_dead_10 = 18
; "Мертвый код 9!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
msg_dead_9: .строкауль "Мертвый код 9!"
.константа len_msg_dead_9 = 18
; "Мертвый код 8!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
msg_dead_8: .строкауль "Мертвый код 8!"
.константа len_msg_dead_8 = 18
; "Мертвый код 7!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
msg_dead_7: .строкауль "Мертвый код 7!"
.константа len_msg_dead_7 = 18
; "Мертвый код 6!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
msg_dead_6: .строкауль "Мертвый код 6!"
.константа len_msg_dead_6 = 18
; "Мертвый код 5!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
msg_dead_5: .строкауль "Мертвый код 5!"
.константа len_msg_dead_5 = 18
; "Мертвый код 4!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
msg_dead_4: .строкауль "Мертвый код 4!"
.константа len_msg_dead_4 = 18
; "Мертвый код 3!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
msg_dead_3: .строкауль "Мертвый код 3!"
.константа len_msg_dead_3 = 18
; "Мертвый код 2!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
msg_dead_2: .строкауль "Мертвый код 2!"
.константа len_msg_dead_2 = 18
; "Мертвый код 1!" = 7 букв * 2 + 4 символа * 1 = 14 + 4 = 18 байт на содержимое. len = 18
msg_dead_1: .строкауль "Мертвый код 1!"
.константа len_msg_dead_1 = 18

View file

@ -1,66 +0,0 @@
.глобал _start
.текст
_start:
нет_операции
вызов_системы
вернуться
втолкнуть раикс
втолкнуть р8
вытолкнуть раикс
вытолкнуть р8
переместить раикс, рбикс
переместить р8, р9
сравнить раикс, рбикс
сравнить р8, р9
проверить раикс, рбикс
проверить р8, р9
прибавить раикс, рбикс
прибавить р8, р9
вычесть раикс, рбикс
вычесть р8, р9
и раикс, рбикс
и р8, р9
или раикс, рбикс
или р8, р9
исключающее_или раикс, рбикс
исключающее_или р8, р9
увеличить раикс
увеличить р8
увеличить еаикс
уменьшить раикс
уменьшить р8
уменьшить еаикс
инвертировать раикс
инвертировать еаикс
отрицать раикс
отрицать еаикс
переместить_имм раикс, 10
переместить_имм рбикс, 5
умножить рбикс
переместить_имм раикс, 100
переместить_имм рбикс, 7
разделить рбикс
умножить_знаковое рбикс
разделить_знаковое рбикс
сдвиг_влево раикс, 2
сдвиг_вправо раикс, 2
сдвиг_арифметический_вправо раикс, 2
вращать_влево раикс, 2
вращать_вправо раикс, 2
переход метка_длинная
короткий_переход меткаороткая
цикл меткаороткая
вызвать метка_длинная
метка_длинная:
нет_операции
нет_операции
нет_операции
меткаороткая:
нет_операции
переместить_имм раикс, 60
переместить_имм рдикс, 0
вызов_системы

View file

@ -1,112 +0,0 @@
.глобал _start
.текст
_start:
; ===== ГРУППА 1: Без операндов (реализованные) =====
нет_операции
вызов_системы
вернуться
; ===== ГРУППА 2: PUSH/POP =====
втолкнуть раикс
втолкнуть р8
вытолкнуть раикс
вытолкнуть р8
; ===== ГРУППА 3: Регистр-регистр =====
переместить раикс, рбикс
переместить р8, р9
сравнить раикс, рбикс
сравнить р8, р9
проверить раикс, рбикс
проверить р8, р9
прибавить раикс, рбикс
прибавить р8, р9
вычесть раикс, рбикс
вычесть р8, р9
и раикс, рбикс
и р8, р9
или раикс, рбикс
или р8, р9
исключающее_или раикс, рбикс
исключающее_или р8, р9
; ===== ГРУППА 4: INC/DEC =====
увеличить раикс
увеличить р8
увеличить еаикс
уменьшить раикс
уменьшить р8
уменьшить еаикс
; ===== ГРУППА 5: NOT/NEG =====
инвертировать раикс
инвертировать еаикс
отрицать раикс
отрицать еаикс
; ===== ГРУППА 6: MUL/DIV =====
переместить_имм раикс, 10
переместить_имм рбикс, 5
умножить рбикс
переместить_имм раикс, 100
переместить_имм рбикс, 7
разделить рбикс
умножить_знаковое рбикс
разделить_знаковое рбикс
; ===== ГРУППА 7: Битовые операции =====
сдвиг_влево раикс, 2
сдвиг_вправо раикс, 2
сдвиг_арифметический_вправо раикс, 2
вращать_влево раикс, 2
вращать_вправо раикс, 2
; ===== ГРУППА 8: Переходы =====
переход метка_длинная
переход_если_равно метка_длинная
переход_если_неравно метка_длинная
переход_если_меньше метка_длинная
переход_если_больше метка_длинная
переход_если_меньше_или_равно метка_длинная
переход_если_больше_или_равно метка_длинная
переход_если_перенос метка_длинная
переход_если_нет_переноса метка_длинная
короткий_переход меткаороткая
короткий_переход_если_равно меткаороткая
короткий_переход_если_неравно меткаороткая
короткий_переход_если_меньше меткаороткая
короткий_переход_если_больше меткаороткая
короткий_переход_если_меньше_или_равно меткаороткая
короткий_переход_если_больше_или_равно меткаороткая
короткий_переход_если_перенос меткаороткая
короткий_переход_если_нет_переноса меткаороткая
цикл меткаороткая
вызвать метка_длинная
метка_длинная:
нет_операции
нет_операции
нет_операции
меткаороткая:
нет_операции
; Выход
переместить_имм раикс, 60
переместить_имм рдикс, 0
вызов_системы

View file

@ -1,27 +0,0 @@
.текст
.глобал _start
_start:
; Счётчик циклов = 5
переместить_имм р8, 5
цикл:
; Выводим сообщение
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg
переместить_имм рдикс, 21
вызов_системы
; Счётчик--
уменьшить р8
сравнить_с р8, 0
короткий_переход_если_неравно цикл
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
msg: .строка "Привет мир!\n"

View file

@ -1,40 +0,0 @@
.текст
.глобал _start
_start:
переместить_имм р9, 1 ; счётчик = 1
цикл:
; Выводим счётчик как цифру
переместить раикс, р9
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; Счётчик++
увеличить р9
сравнить_с р9, 7 ; до 7 (1..6)
короткий_переход_если_неравно цикл
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
буфер:
.байт 0, 0, 0, 0, 0, 0, 0, 0
nl:
.байт 0x0A

View file

@ -1,40 +0,0 @@
.текст
.глобал _start
_start:
переместить_имм р9, 6 ; счётчик = 6
цикл:
; Выводим счётчик как цифру
переместить раикс, р9
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; Счётчик--
уменьшить р9
сравнить_с р9, 0 ; до 0
короткий_переход_если_неравно цикл
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
буфер:
.байт 0, 0, 0, 0, 0, 0, 0, 0
nl:
.байт 0x0A

View file

@ -1,45 +0,0 @@
.текст
.глобал _start
_start:
переместить_имм р8, 1 ; число = 1
цикл:
; Выводим число
переместить раикс, р8
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; Умножаем на 2
переместить раикс, р8
переместить_имм р9, 2
умножить р9
переместить р8, раикс
; Продолжаем пока < 10
сравнить_с р8, 10
переход_если_меньше цикл ; длинный переход вместо короткого
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
буфер:
.байт 0, 0, 0, 0, 0, 0, 0, 0
nl:
.байт 0x0A

View file

@ -1,86 +0,0 @@
.текст
.глобал _start
_start:
переместить_имм р8, 2 ; число = 2
цикл:
; Если число < 10 — выводим как есть
сравнить_с р8, 10
переход_если_больше_или_равно двузначное
; Однозначное: просто цифра
переместить раикс, р8
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
переход продолжение
двузначное:
; Делим на 10
переместить раикс, р8
переместить_имм рдикс, 0
переместить_имм рсикс, 10
разделить рсикс ; rax = десятки, rdx = единицы
; Сохраняем единицы в .бнд (пока не испортились)
сохранить [остаток], рдикс
; Выводим десятки
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Загружаем единицы обратно
загрузить рдикс, [остаток]
; Выводим единицы
прибавить_непосредственно рдикс, 0x30
сохранить [буфер], рдикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
продолжение:
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; Прибавляем 2
прибавить_непосредственно р8, 2
; Продолжаем пока <= 99
сравнить_с р8, 99
переход_если_меньше цикл
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
буфер:
.байт 0, 0, 0, 0, 0, 0, 0, 0
nl:
.байт 0x0A
.бнд
остаток:
.резб 8

View file

@ -1,81 +0,0 @@
.текст
.глобал _start
_start:
; Тест: выводим длины чисел от 0 до 20
переместить_имм р8, 0 ; число = 0
цикл:
; Считаем длину числа
переместить раикс, р8
вызвать длина_числа
; Выводим длину как цифру
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; Число++
увеличить р8
сравнить_с р8, 21 ; 0..20
переход_если_меньше цикл
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
; =============================================
; длина_числа: количество десятичных цифр в rax
; Вход: rax = число
; Выход: rax = количество цифр
; =============================================
длина_числа:
втолкнуть р8
втолкнуть р9
переместить р8, раикс ; р8 = число
переместить_имм р9, 0 ; счётчик = 0
сравнить_с р8, 0
короткий_переход_если_неравно длина_цикл
переместить_имм раикс, 1 ; 0 = 1 цифра
вытолкнуть р9
вытолкнуть р8
вернуться
длина_цикл:
увеличить р9
переместить раикс, р8
переместить_имм рдикс, 0
переместить_имм рсикс, 10
разделить рсикс
переместить р8, раикс
сравнить_с р8, 0
короткий_переход_если_неравно длина_цикл
переместить раикс, р9
вытолкнуть р9
вытолкнуть р8
вернуться
.данные
буфер:
.байт 0, 0, 0, 0, 0, 0, 0, 0
nl:
.байт 0x0A

View file

@ -1,138 +0,0 @@
.текст
.глобал _start
_start:
переместить_имм р8, 0 ; число = 0
цикл:
; Выводим число (костыльно: до 99)
сравнить_с р8, 10
переход_если_больше_или_равно двузначное
; Однозначное
переместить раикс, р8
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
переход показать_длину
двузначное:
; Делим на 10
переместить раикс, р8
переместить_имм рдикс, 0
переместить_имм рсикс, 10
разделить рсикс
сохранить [остаток], рдикс
; Десятки
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Единицы
загрузить рдикс, [остаток]
прибавить_непосредственно рдикс, 0x30
сохранить [буфер], рдикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
показать_длину:
; Разделитель: " -> "
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, стрелка
переместить_имм рдикс, 4
вызов_системы
; Длина числа
переместить раикс, р8
вызвать длина_числа
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; Число++
увеличить р8
сравнить_с р8, 9199
переход_если_меньше цикл
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
; =============================================
; длина_числа
; =============================================
длина_числа:
втолкнуть р8
втолкнуть р9
переместить р8, раикс
переместить_имм р9, 0
сравнить_с р8, 0
короткий_переход_если_неравно длина_цикл
переместить_имм раикс, 1
вытолкнуть р9
вытолкнуть р8
вернуться
длина_цикл:
увеличить р9
переместить раикс, р8
переместить_имм рдикс, 0
переместить_имм рсикс, 10
разделить рсикс
переместить р8, раикс
сравнить_с р8, 0
короткий_переход_если_неравно длина_цикл
переместить раикс, р9
вытолкнуть р9
вытолкнуть р8
вернуться
.данные
буфер:
.байт 0, 0, 0, 0, 0, 0, 0, 0
стрелка:
.строка " -> "
nl:
.байт 0x0A
.бнд
остаток:
.резб 8

View file

@ -1,180 +0,0 @@
.текст
.глобал _start
_start:
; МЕНЯЙ ЧИСЛО ЗДЕСЬ:
переместить_имм р8, 456777
; Выводим число через itoa3 (до 999!)
переместить раикс, р8
переместить_имм рдиай, буфер
вызвать itoa3
загрузить рсиай, [указатель]
загрузить рдикс, [длина]
переместить_имм раикс, 1
переместить_имм рдиай, 1
вызов_системы
; " -> "
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, стрелка
переместить_имм рдикс, 4
вызов_системы
; Длина числа
переместить раикс, р8
вызвать длина_числа
; Выводим длину
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
; =============================================
; itoa3 — работает для чисел до 999
; =============================================
itoa3:
втолкнуть рбикс
втолкнуть р8
втолкнуть р9
переместить рбикс, рдиай
переместить р8, раикс
сравнить_с р8, 10
переход_если_меньше одна_цифра
сравнить_с р8, 100
переход_если_меньше две_цифры
; Три цифры
прибавить_непосредственно рбикс, 3
переместить раикс, р8
переместить_имм рдикс, 0
переместить_имм р9, 10
разделить р9
прибавить_непосредственно рдикс, 0x30
уменьшить рбикс
сохранить [рбикс], рдикс
переместить р8, раикс
переместить раикс, р8
переместить_имм рдикс, 0
разделить р9
прибавить_непосредственно рдикс, 0x30
уменьшить рбикс
сохранить [рбикс], рдикс
прибавить_непосредственно раикс, 0x30
уменьшить рбикс
сохранить [рбикс], раикс
сохранить [указатель], рбикс
переместить_имм раикс, 3
сохранить [длина], раикс
вытолкнуть р9
вытолкнуть р8
вытолкнуть рбикс
вернуться
две_цифры:
прибавить_непосредственно рбикс, 2
переместить раикс, р8
переместить_имм рдикс, 0
переместить_имм р9, 10
разделить р9
прибавить_непосредственно рдикс, 0x30
уменьшить рбикс
сохранить [рбикс], рдикс
прибавить_непосредственно раикс, 0x30
уменьшить рбикс
сохранить [рбикс], раикс
сохранить [указатель], рбикс
переместить_имм раикс, 2
сохранить [длина], раикс
вытолкнуть р9
вытолкнуть р8
вытолкнуть рбикс
вернуться
одна_цифра:
прибавить_непосредственно раикс, 0x30
сохранить [рбикс], раикс
сохранить [указатель], рбикс
переместить_имм раикс, 1
сохранить [длина], раикс
вытолкнуть р9
вытолкнуть р8
вытолкнуть рбикс
вернуться
; =============================================
; длина_числа
; =============================================
длина_числа:
втолкнуть р8
втолкнуть р9
переместить р8, раикс
переместить_имм р9, 0
сравнить_с р8, 0
короткий_переход_если_неравно длина_цикл
переместить_имм раикс, 1
вытолкнуть р9
вытолкнуть р8
вернуться
длина_цикл:
увеличить р9
переместить раикс, р8
переместить_имм рдикс, 0
переместить_имм рсикс, 10
разделить рсикс
переместить р8, раикс
сравнить_с р8, 0
короткий_переход_если_неравно длина_цикл
переместить раикс, р9
вытолкнуть р9
вытолкнуть р8
вернуться
.данные
буфер:
.байт 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
стрелка:
.строка " -> "
nl:
.байт 0x0A
.бнд
указатель:
.резб 8
длина:
.резб 8

View file

@ -1,77 +0,0 @@
.текст
.глобал _start
_start:
; МЕНЯЙ ЧИСЛО:
переместить_имм р8, 750
; Выводим число (костыльно: делим на 100, потом на 10)
сравнить_с р8, 100
переход_если_меньше меньше_100
; >= 100: делим на 100
переместить раикс, р8
переместить_имм рдикс, 0
переместить_имм рсикс, 100
разделить рсикс ; rax = сотни, rdx = остаток
; Выводим сотни
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Остаток — продолжаем
переместить р8, рдикс
меньше_100:
; Делим на 10
сравнить_с р8, 10
переход_если_меньше меньше_10
переместить раикс, р8
переместить_имм рдикс, 0
переместить_имм рсикс, 10
разделить рсикс
; Выводим десятки
прибавить_непосредственно раикс, 0x30
сохранить [буфер], раикс
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
переместить р8, рдикс
меньше_10:
; Выводим единицы
прибавить_непосредственно р8, 0x30
сохранить [буфер], р8
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, буфер
переместить_имм рдикс, 1
вызов_системы
; Перевод строки
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, nl
переместить_имм рдикс, 1
вызов_системы
; exit(0)
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
буфер:
.байт 0, 0, 0, 0, 0, 0, 0, 0
nl:
.байт 0x0A