diff --git a/kvs_build.py b/kvs_build.py index 46c8931..098e61c 100644 --- a/kvs_build.py +++ b/kvs_build.py @@ -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}") \ No newline at end of file + #print(f"\n=== Компиляция успешно завершена ===") + #print(f"Исполняемый файл: {elf_file}") + #print(f"Запустить: ./{elf_file}") \ No newline at end of file diff --git a/kvs_builder.py b/kvs_builder.py index 274562f..5f6d136 100644 --- a/kvs_builder.py +++ b/kvs_builder.py @@ -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(' 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(' 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]) \ No newline at end of file + 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() \ No newline at end of file diff --git a/kvs_pass2_encoder.py b/kvs_encoder.py similarity index 100% rename from kvs_pass2_encoder.py rename to kvs_encoder.py diff --git a/kvs_pass2_encoder_fixsize.py b/kvs_encoder_fixsize.py similarity index 100% rename from kvs_pass2_encoder_fixsize.py rename to kvs_encoder_fixsize.py diff --git a/kvs_pass2_encoder_mutsize.py b/kvs_encoder_mutsize.py similarity index 100% rename from kvs_pass2_encoder_mutsize.py rename to kvs_encoder_mutsize.py diff --git a/kvs_pass1.py b/kvs_pass1.py index 8530bd8..1451093 100644 --- a/kvs_pass1.py +++ b/kvs_pass1.py @@ -2,22 +2,158 @@ # -*- coding: utf-8 -*- """ -Первый проход КВС -Вычисляет размеры секций и адреса меток +Первый проход КВС (однопроходная версия с заглушками) +Генерирует CSV-таблицу напрямую из AST +- Неизвестные метки заменяются заглушками (0xCC) с пометкой в колонке 'уводящий_адрес' +- В колонке 'приводящая_метка' записываются имена меток, находящихся по данному адресу (через запятую) +- Колонка 'команда_со_значениями' оставлена пустой (для возможного расширения) +- Колонки 'рассчитанный_уводящий_адрес' и 'рассчитанный_байт' оставлены для второго прохода """ import sys -sys.path.insert(0, '.') -from kvs_data import PAGE_SIZE, text_vaddr_base, align_up, INSTRUCTIONS -from kvs_data import FIXED_SIZE_INSTRUCTIONS, VARIABLE_SIZE_INSTRUCTIONS +import csv + +sys.path.insert(0, '.') +from kvs_data import PAGE_SIZE, text_vaddr_base, align_up +from kvs_encoder import encode_instruction + +# ========== ГЛОБАЛЬНОЕ СОСТОЯНИЕ ========== +entries = [] # (segment, address, byte, target, source, label, source_with_values, calc_target, calc_byte) +current_address = 0 +current_segment = '.header' +last_segment = None + +vaddr_text = text_vaddr_base +vaddr_data = None +vaddr_bnd = None + +text_buffer = bytearray() +data_buffer = bytearray() +bnd_size = 0 + +labels = {} # имя метки -> адрес +label_sections = {} # имя метки -> секция +symbols = {} # имя константы -> значение + +# Для сбора нескольких меток на один адрес +pending_labels = [] # список имён меток, ожидающих привязки к следующему байту + +text_pos = 0 +data_pos = 0 + +entry_point = "_start" +relocations = [] + + +def reset_state(): + global entries, current_address, current_segment, last_segment + global text_buffer, data_buffer, bnd_size, vaddr_data, vaddr_bnd + global labels, label_sections, symbols, text_pos, data_pos, entry_point, relocations + global pending_labels + + entries = [] + current_address = 0 + current_segment = '.header' + last_segment = None + text_buffer = bytearray() + data_buffer = bytearray() + bnd_size = 0 + vaddr_data = None + vaddr_bnd = None + labels = {} + label_sections = {} + symbols = {} + text_pos = 0 + data_pos = 0 + entry_point = "_start" + relocations = [] + pending_labels = [] + + +def set_segment(segment: str): + global current_segment + current_segment = segment + + +def add_byte(value: int, source: str = "", target=None, labels_list=None): + """Добавить один байт в текущую позицию""" + global current_address, last_segment, pending_labels + + # Если есть отложенные метки, объединяем их через запятую + effective_labels = "" + if labels_list is not None and labels_list: + effective_labels = ','.join(labels_list) + elif pending_labels: + effective_labels = ','.join(pending_labels) + + show_segment = current_segment if current_segment != last_segment else None + if show_segment: + last_segment = current_segment + + entries.append(( + show_segment if show_segment else "", # segment + current_address, # address + value & 0xFF, # byte + target if target else "", # target (уводящий_адрес) + source, # source (исходная_команда) + effective_labels, # label (приводящая_метка) - несколько через запятую + "", # source_with_values (команда_со_значениями) - всегда пусто + "", # calc_target + "" # calc_byte + )) + current_address += 1 + + # После добавления байта сбрасываем отложенные метки + if pending_labels: + pending_labels = [] + + +def add_bytes(values, source: str = "", target=None): + for i, v in enumerate(values): + add_byte(v, source if i == 0 else "", target if i == 0 else None) + + +def add_word16(value: int, source: str = "", target=None): + """Добавить 16-битное слово (little-endian)""" + add_bytes([ + (value >> 0) & 0xFF, + (value >> 8) & 0xFF, + ], source, target) + + +def add_word32(value: int, source: str = "", target=None): + """Добавить 32-битное слово (little-endian)""" + add_bytes([ + (value >> 0) & 0xFF, + (value >> 8) & 0xFF, + (value >> 16) & 0xFF, + (value >> 24) & 0xFF, + ], source, target) + + +def add_word64(value: int, source: str = "", target=None): + """Добавить 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, target) + + +def align_to(alignment: int): + global current_address, pending_labels + padding = (alignment - (current_address % alignment)) % alignment + if padding > 0: + pending_labels = [] + current_address += padding -# ========== РЕЖИМ ОЦЕНКИ РАЗМЕРОВ ========== -# True — пессимистичный: все неизвестные инструкции = 10 байт (максимум) -# False — оптимистичный: использовать точный анализ операндов -PESSIMISTIC_SIZE_ESTIMATE = False def unescape_string(s): - """Преобразует escape-последовательности в реальные символы""" result = [] i = 0 while i < len(s): @@ -29,7 +165,6 @@ def unescape_string(s): elif s[i + 1] == 'r': result.append('\r') else: - result.append(s[i]) result.append(s[i + 1]) i += 2 else: @@ -37,364 +172,593 @@ def unescape_string(s): i += 1 return ''.join(result) + +def generate_elf_header(): + # EI_MAGIC + add_bytes([0x7F, 0x45, 0x4C, 0x46], "ELF magic") + # EI_CLASS, EI_DATA, EI_VERSION + add_byte(2, "ELFCLASS64") + add_byte(1, "ELFDATA2LSB") + add_byte(1, "ELF version") + # EI_OSABI, EI_ABIVERSION + add_byte(0, "OS ABI") + add_byte(0, "ABI version") + # EI_PAD + add_bytes([0] * 7, "Padding") + + # e_type (2 байта) + add_word16(2, "e_type = ET_EXEC") + # e_machine (2 байта) + add_word16(62, "e_machine = EM_X86_64") + # e_version (4 байта) + add_word32(1, "e_version") + # e_entry (8 байт, заглушка) + add_word64(0, "e_entry (stub)") + # e_phoff (8 байт) + add_word64(64, "e_phoff") + # e_shoff (8 байт) + add_word64(0, "e_shoff = 0") + # e_flags (4 байта) + add_word32(0, "e_flags") + # e_ehsize (2 байта) + add_word16(64, "e_ehsize") + # e_phentsize (2 байта) + add_word16(56, "e_phentsize") + # e_phnum (2 байта) + add_word16(2, "e_phnum = 2") + # e_shentsize (2 байта) + add_word16(0, "e_shentsize = 0") + # e_shnum (2 байта) + add_word16(0, "e_shnum = 0") + # e_shstrndx (2 байта) + add_word16(0, "e_shstrndx") + + +def generate_program_headers(): + # Program Header 1: TEXT (RX) + add_word32(1, "p_type = PT_LOAD") + add_word32(5, "p_flags = RX") + add_word64(0, "p_offset (text stub)") + add_word64(vaddr_text, "p_vaddr (text)") + add_word64(vaddr_text, "p_paddr (text)") + add_word64(0, "p_filesz (text stub)") + add_word64(0, "p_memsz (text stub)") + add_word64(PAGE_SIZE, "p_align") + + # Program Header 2: DATA (RW) + add_word32(1, "p_type = PT_LOAD") + add_word32(6, "p_flags = RW") + add_word64(0, "p_offset (data stub)") + add_word64(0, "p_vaddr (data stub)") + add_word64(0, "p_paddr (data stub)") + add_word64(0, "p_filesz (data stub)") + add_word64(0, "p_memsz (data stub)") + add_word64(PAGE_SIZE, "p_align") + + def read_ast(input_file): - ast_lines = [] with open(input_file, 'r', encoding='utf-8') as f: - for line in f: - ast_lines.append(line.strip()) - return ast_lines + return [line.strip() for line in f] -def is_hex_number(s): - """Проверяет, является ли строка шестнадцатеричным числом""" - if len(s) < 3: - return False - if not (s[0] == '0' and (s[1] == 'x' or s[1] == 'X')): - return False - for ch in s[2:]: - if not (('0' <= ch <= '9') or ('a' <= ch <= 'f') or ('A' <= ch <= 'F')): - return False - return True -def is_dec_number(s): - """Проверяет, является ли строка десятичным числом (возможно с минусом)""" - if not s: - return False - start = 0 - if s[0] == '-': - if len(s) == 1: - return False - start = 1 - for ch in s[start:]: - if ch < '0' or ch > '9': - return False - return True - -def is_register(s): - """Проверяет, является ли строка именем регистра""" - return s in ['раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай', - 'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'] - -def split_by_operators(content): - """ - Разбивает строку по операторам + и - с сохранением операторов. - Аналог re.split(r'([+\-])', content) - Пример: "раикс + рбикс*4 - 8" -> ["раикс ", "+", " рбикс*4 ", "-", " 8"] - """ - parts = [] - current = '' - for ch in content: - if ch == '+' or ch == '-': - if current: - parts.append(current) - parts.append(ch) - current = '' +def parse_ast_line(line): + if not line: + return None, {} + + line_type = line.split(':')[0] + + if line_type == "INSTR": + first = line.find(':') + second = line.find(':', first + 1) + third = line.find(':', second + 1) + + if first == -1 or second == -1 or third == -1: + return "INSTR", {} + + mnemonic = line[first + 1:second] + section = line[second + 1:third] + operands_str = line[third + 1:] + + operands = operands_str.split(',') if operands_str else [] + + return "INSTR", { + 'mnemonic': mnemonic, + 'section': section, + 'operands': operands + } + + elif line_type == "DIRECTIVE": + parts = line.split(':') + directive = parts[1] if len(parts) > 1 else "" + + if directive in ('.текст', '.данные', '.бнд'): + return "DIRECTIVE", {'directive': directive} + elif directive == '.глобал': + return "DIRECTIVE", {'directive': directive, 'label': parts[2] if len(parts) > 2 else ""} + elif directive in ('.строка', '.строка_нуль'): + return "DIRECTIVE", { + 'directive': directive, + 'section': parts[2] if len(parts) > 2 else "", + 'string': parts[3] if len(parts) > 3 else "" + } + elif directive == '.константа': + return "DIRECTIVE", { + 'directive': directive, + 'name': parts[2] if len(parts) > 2 else "", + 'value': parts[3] if len(parts) > 3 else "" + } + elif directive == '.байт': + return "DIRECTIVE", { + 'directive': directive, + 'section': parts[2] if len(parts) > 2 else "", + 'bytes': parts[3] if len(parts) > 3 else "" + } + elif directive in ('.резб', '.резс', '.рездс', '.резкс'): + return "DIRECTIVE", { + 'directive': directive, + 'section': parts[2] if len(parts) > 2 else "", + 'count': parts[3] if len(parts) > 3 else "0" + } else: - current += ch - if current: - parts.append(current) - return parts + return "DIRECTIVE", {'directive': directive} + + elif line_type == "LABEL": + parts = line.split(':') + return "LABEL", { + 'name': parts[1] if len(parts) > 1 else "", + 'section': parts[2] if len(parts) > 2 else "" + } + + return line_type, {} -def parse_memory_operand(operand_str): - """ - Анализирует операнд памяти вида [reg + reg*scale + disp] - Возвращает словарь с информацией. - """ - if not operand_str.startswith('[') or not operand_str.endswith(']'): - return None - - content = operand_str[1:-1].strip() - if not content: - return None - - result = { - 'has_base': False, - 'base_reg': None, - 'has_index': False, - 'index_reg': None, - 'scale': 1, - 'has_disp': False, - 'disp_value': 0, - 'disp_size': 0 - } - - if is_dec_number(content) or is_hex_number(content): - result['has_disp'] = True - if content.startswith('0x') or content.startswith('0X'): - result['disp_value'] = int(content, 16) + +def get_stub_size(mnemonic, operands): + if mnemonic == "переместить_имм" and len(operands) >= 2: + reg = operands[0] + if reg in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай', + 'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'): + return 10 + elif reg in ('еаикс', 'ебикс', 'есикс', 'едикс'): + return 7 else: - result['disp_value'] = int(content) - result['disp_size'] = 4 - return result + return 2 + elif mnemonic in ("переход", "вызвать"): + return 5 + elif mnemonic.startswith("короткий_переход"): + return 2 + elif mnemonic.startswith("переход_если"): + return 6 + elif mnemonic.startswith("короткий_переход_если"): + return 2 + elif mnemonic in ("загрузить", "сохранить", "загрузить_адрес"): + return 7 + return 1 + + +def has_unresolved_labels(operands): + for op in operands: + if not op: + continue + if op in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай', + 'р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15', + 'еаикс', 'ебикс', 'есикс', 'едикс', + 'аикс', 'бикс', 'сикс', 'дикс', + 'ал', 'бл', 'кл', 'дл'): + continue + if op.startswith('[') and op.endswith(']'): + inner = op[1:-1] + if inner in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай'): + continue + if inner in labels: + continue + if inner.isdigit() or (inner.startswith('0x')): + continue + return True + elif op in labels: + continue + elif op.isdigit() or (op.startswith('0x')): + continue + else: + if op in symbols: + continue + return True + return False + + +def get_unresolved_labels(operands): + unresolved = [] + for op in operands: + if not op: + continue + if op.startswith('[') and op.endswith(']'): + inner = op[1:-1] + if inner not in labels and not inner.isdigit() and not (inner.startswith('0x')): + if inner not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай'): + if inner not in symbols: + unresolved.append(inner) + elif op not in labels and not op.isdigit() and not (op.startswith('0x')): + if op not in ('раикс', 'рбикс', 'рсикс', 'рдикс', 'рсипи', 'рбипи', 'рсиай', 'рдиай', + 'еаикс', 'ебикс', 'есикс', 'едикс', + 'аикс', 'бикс', 'сикс', 'дикс', + 'ал', 'бл', 'кл', 'дл'): + if op not in symbols: + unresolved.append(op) + return unresolved + + +def process_ast_line(line): + global text_pos, data_pos, vaddr_data, vaddr_bnd, bnd_size + global text_buffer, data_buffer, entry_point, symbols, pending_labels - if is_register(content): - result['has_base'] = True - result['base_reg'] = content - return result + line_type, fields = parse_ast_line(line) - parts = split_by_operators(content) + if line_type == "DIRECTIVE": + directive = fields.get('directive', '') + + if directive == '.текст': + set_segment('.text') + + elif directive == '.данные': + set_segment('.data') + align_to(PAGE_SIZE) + + elif directive == '.бнд': + set_segment('.bss') + + elif directive == '.глобал': + entry_point = fields.get('label', '_start') + + elif directive == '.константа': + name = fields.get('name', '') + value_str = fields.get('value', '') + 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}") + + elif directive in ('.строка', '.строка_нуль'): + s = fields.get('string', '') + real_s = unescape_string(s) + bstring = real_s.encode('utf-8') + if directive == '.строка_нуль': + bstring += b'\x00' + + source = f'{directive} "{s}"' + + for i, byte in enumerate(bstring): + labels_list = pending_labels if i == 0 else None + add_byte(byte, source if i == 0 else "", None, labels_list) + data_buffer.append(byte) + if labels_list: + pending_labels = [] + data_pos += len(bstring) + + elif directive == '.байт': + bytes_str = fields.get('bytes', '') + if bytes_str: + byte_values = bytes_str.split(',') + source = f'.байт {bytes_str}' + bstring = bytearray() + for byte_str in byte_values: + byte_str = byte_str.strip() + if byte_str.startswith('0x'): + val = int(byte_str, 16) + else: + val = int(byte_str) + bstring.append(val & 0xFF) + + for i, byte in enumerate(bstring): + labels_list = pending_labels if i == 0 else None + add_byte(byte, source if i == 0 else "", None, labels_list) + data_buffer.append(byte) + if labels_list: + pending_labels = [] + data_pos += len(bstring) + + elif directive in ('.резб', '.резс', '.рездс', '.резкс'): + count = int(fields.get('count', '0')) + multiplier = {'резб': 1, 'резс': 2, 'рездс': 4, 'резкс': 8} + bnd_size += count * multiplier.get(directive, 1) - for part in parts: - part = part.strip() - if not part or part == '+' or part == '-': + elif line_type == "LABEL": + label_name = fields.get('name', '') + sec = fields.get('section', '') + + if sec == '.text': + addr = vaddr_text + text_pos + labels[label_name] = addr + label_sections[label_name] = sec + if label_name not in pending_labels: + pending_labels.append(label_name) + + elif sec == '.data': + if vaddr_data is None: + vaddr_data = align_up(vaddr_text + text_pos, PAGE_SIZE) + addr = vaddr_data + data_pos + labels[label_name] = addr + label_sections[label_name] = sec + if label_name not in pending_labels: + pending_labels.append(label_name) + + elif sec == '.бнд': + if vaddr_bnd is None: + vaddr_bnd = align_up(vaddr_data + data_pos, PAGE_SIZE) + addr = vaddr_bnd + bnd_size + labels[label_name] = addr + label_sections[label_name] = sec + if label_name not in pending_labels: + pending_labels.append(label_name) + + else: + addr = current_address + labels[label_name] = addr + label_sections[label_name] = sec + if label_name not in pending_labels: + pending_labels.append(label_name) + + elif line_type == "INSTR": + mnemonic = fields.get('mnemonic', '') + sec = fields.get('section', '') + operands = fields.get('operands', []) + + source = f"{mnemonic} {', '.join(operands)}" if operands else mnemonic + + source_with_values = "" + + if has_unresolved_labels(operands): + stub_size = get_stub_size(mnemonic, operands) + unresolved = get_unresolved_labels(operands) + reloc_text = f"ЗАГЛУШКА {', '.join(unresolved)}" + + relocations.append({ + 'address': current_address, + 'size': stub_size, + 'labels': unresolved, + 'source': source, + 'mnemonic': mnemonic + }) + + for i in range(stub_size): + labels_list = pending_labels if i == 0 else None + add_byte(0xCC, source if i == 0 else "", reloc_text if i == 0 else None, labels_list) + if labels_list: + pending_labels = [] + + if sec == '.text': + text_buffer.extend([0xCC] * stub_size) + text_pos += stub_size + else: + data_buffer.extend([0xCC] * stub_size) + data_pos += stub_size + else: + try: + if sec == '.text': + current_pos = text_pos + else: + current_pos = data_pos + + 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 i, byte in enumerate(encoded): + labels_list = pending_labels if i == 0 else None + add_byte(byte, source if i == 0 else "", None, labels_list) + if labels_list: + pending_labels = [] + + if sec == '.text': + text_buffer.extend(encoded) + text_pos += len(encoded) + else: + data_buffer.extend(encoded) + data_pos += len(encoded) + + except Exception as e: + print(f"Ошибка кодирования {source}: {e}", file=sys.stderr) + labels_list = pending_labels + add_byte(0xCC, source, None, f"ОШИБКА: {e}", labels_list) + pending_labels = [] + + if sec == '.text': + text_buffer.append(0xCC) + text_pos += 1 + else: + data_buffer.append(0xCC) + data_pos += 1 + + +def finalize_headers(): + global entries + + text_offset = 0x1000 + data_offset = 0x2000 + + text_filesz = len(text_buffer) + text_memsz = len(text_buffer) + + data_filesz = len(data_buffer) + data_memsz = len(data_buffer) + bnd_size + + vaddr_data_final = align_up(vaddr_text + text_filesz, PAGE_SIZE) + entry_point_addr = labels.get(entry_point, vaddr_text) + + i = 0 + while i < len(entries): + segment, addr, byte, target, source, label, source_with_values, calc_target, calc_byte = entries[i] + + # e_entry - 8 байт + if 'e_entry (stub)' in source: + new_bytes = [(entry_point_addr >> j*8) & 0xFF for j in range(8)] + for j, nb in enumerate(new_bytes): + entries[i + j] = (segment, addr + j, nb, target, + f"e_entry = 0x{entry_point_addr:x}", + label if j == 0 else "", + "", "", + f"0x{nb:02x}") + i += 8 continue - if is_register(part): - if not result['has_base']: - result['has_base'] = True - result['base_reg'] = part - elif not result['has_index']: - result['has_index'] = True - result['index_reg'] = part - elif is_dec_number(part) or is_hex_number(part): - result['has_disp'] = True - if part.startswith('0x') or part.startswith('0X'): - result['disp_value'] = int(part, 16) - else: - result['disp_value'] = int(part) - elif '*' in part: - star_pos = part.find('*') - if star_pos != -1: - reg_part = part[:star_pos].strip() - scale_part = part[star_pos + 1:].strip() - if is_register(reg_part): - result['has_index'] = True - result['index_reg'] = reg_part - result['scale'] = int(scale_part) - - if result['has_disp']: - if -128 <= result['disp_value'] <= 127: - result['disp_size'] = 1 - else: - result['disp_size'] = 4 - - return result + # p_offset (text) - 8 байт + elif 'p_offset (text stub)' in source: + new_bytes = [(text_offset >> j*8) & 0xFF for j in range(8)] + for j, nb in enumerate(new_bytes): + entries[i + j] = (segment, addr + j, nb, target, + f"p_offset (text) = 0x{text_offset:x}", + label if j == 0 else "", + "", "", + f"0x{nb:02x}") + i += 8 + continue + + # p_filesz (text) - 8 байт + elif 'p_filesz (text stub)' in source: + new_bytes = [(text_filesz >> j*8) & 0xFF for j in range(8)] + for j, nb in enumerate(new_bytes): + entries[i + j] = (segment, addr + j, nb, target, + f"p_filesz (text) = {text_filesz}", + label if j == 0 else "", + "", "", + f"0x{nb:02x}") + i += 8 + continue + + # p_memsz (text) - 8 байт + elif 'p_memsz (text stub)' in source: + new_bytes = [(text_memsz >> j*8) & 0xFF for j in range(8)] + for j, nb in enumerate(new_bytes): + entries[i + j] = (segment, addr + j, nb, target, + f"p_memsz (text) = {text_memsz}", + label if j == 0 else "", + "", "", + f"0x{nb:02x}") + i += 8 + continue + + # p_offset (data) - 8 байт + elif 'p_offset (data stub)' in source: + new_bytes = [(data_offset >> j*8) & 0xFF for j in range(8)] + for j, nb in enumerate(new_bytes): + entries[i + j] = (segment, addr + j, nb, target, + f"p_offset (data) = 0x{data_offset:x}", + label if j == 0 else "", + "", "", + f"0x{nb:02x}") + i += 8 + continue + + # p_vaddr (data) - 8 байт + elif 'p_vaddr (data stub)' in source: + new_bytes = [(vaddr_data_final >> j*8) & 0xFF for j in range(8)] + for j, nb in enumerate(new_bytes): + entries[i + j] = (segment, addr + j, nb, target, + f"p_vaddr (data) = 0x{vaddr_data_final:x}", + label if j == 0 else "", + "", "", + f"0x{nb:02x}") + i += 8 + continue + + # p_paddr (data) - 8 байт + elif 'p_paddr (data stub)' in source: + new_bytes = [(vaddr_data_final >> j*8) & 0xFF for j in range(8)] + for j, nb in enumerate(new_bytes): + entries[i + j] = (segment, addr + j, nb, target, + f"p_paddr (data) = 0x{vaddr_data_final:x}", + label if j == 0 else "", + "", "", + f"0x{nb:02x}") + i += 8 + continue + + # p_filesz (data) - 8 байт + elif 'p_filesz (data stub)' in source: + new_bytes = [(data_filesz >> j*8) & 0xFF for j in range(8)] + for j, nb in enumerate(new_bytes): + entries[i + j] = (segment, addr + j, nb, target, + f"p_filesz (data) = {data_filesz}", + label if j == 0 else "", + "", "", + f"0x{nb:02x}") + i += 8 + continue + + # p_memsz (data) - 8 байт + elif 'p_memsz (data stub)' in source: + new_bytes = [(data_memsz >> j*8) & 0xFF for j in range(8)] + for j, nb in enumerate(new_bytes): + entries[i + j] = (segment, addr + j, nb, target, + f"p_memsz (data) = {data_memsz}", + label if j == 0 else "", + "", "", + f"0x{nb:02x}") + i += 8 + continue + + i += 1 -def estimate_memory_operand_size(operand_str): - """Оценивает размер операнда памяти в байтах (ModR/M + SIB + disp)""" - if not operand_str: - return 0 - - addr_mode = parse_memory_operand(operand_str) - if addr_mode is None: - return 0 - - size = 1 - - if addr_mode['has_index']: - size += 1 - - if addr_mode['has_disp']: - size += addr_mode['disp_size'] - - return size -class Pass1: - def __init__(self): - self.labels = {} - self.label_sections = {} - self.symbols = {} - self.position = {".text": 0, ".data": 0, ".бнд": 0} - self.current_section = ".text" - self.entry_point = "_start" +def save_to_csv(filename: str): + with open(filename, 'w', newline='', encoding='utf-8') as f: + writer = csv.writer(f, delimiter=';') + writer.writerow(['сегмент', 'адрес', 'байт', 'приводящая_метка', 'уводящий_адрес', + 'исходная_команда', 'команда_со_значениями', + 'рассчитанный_уводящий_адрес', 'рассчитанный_байт']) - def process_line(self, line): - parts = line.split(':') - line_type = parts[0] - - if line_type == "DIRECTIVE": - directive = parts[1] - if directive == '.текст': - self.current_section = ".text" - elif directive == '.данные': - self.current_section = ".data" - elif directive == '.бнд': - self.current_section = ".бнд" - elif directive == '.глобал': - self.entry_point = parts[2] - elif directive in ('.строка_нуль', '.строка'): - s = parts[3] if len(parts) > 3 else "" - real_s = unescape_string(s) - bstring = real_s.encode('utf-8') - add_null = (directive == '.строка_нуль') - size = len(bstring) + (1 if add_null else 0) - self.position[".data"] += size - elif directive == '.константа': - name = parts[2] - value_str = parts[3] - if is_dec_number(value_str): - self.symbols[name] = int(value_str) - elif is_hex_number(value_str): - self.symbols[name] = int(value_str, 16) - else: - self.symbols[name] = 0 - elif directive == '.байт': - sec = parts[2] - if len(parts) > 3 and parts[3]: - num_bytes = 1 - for ch in parts[3]: - if ch == ',': - num_bytes += 1 - self.position[sec] += num_bytes - elif directive == '.резб': - count = int(parts[3]) - self.position['.бнд'] += count * 1 - elif directive == '.резс': - count = int(parts[3]) - self.position['.бнд'] += count * 2 - elif directive == '.рездс': - count = int(parts[3]) - self.position['.бнд'] += count * 4 - elif directive == '.резкс': - count = int(parts[3]) - self.position['.бнд'] += count * 8 - - elif line_type == "LABEL": - label_name = parts[1] - sec = parts[2] - self.labels[label_name] = self.position[sec] - self.label_sections[label_name] = sec - - elif line_type == "INSTR": - mnemonic = parts[1] - sec = parts[2] - operands_str = parts[3] if len(parts) > 3 else "" - operands = [] - if operands_str: - current = '' - for ch in operands_str: - if ch == ',': - operands.append(current) - current = '' - else: - current += ch - if current: - operands.append(current) - size = self.estimate_size(mnemonic, operands) - self.position[sec] += size - - def estimate_size(self, mnemonic, operands): - """Динамический расчёт размера инструкции""" - - # Инструкции с фиксированным размером - if mnemonic in FIXED_SIZE_INSTRUCTIONS: - return FIXED_SIZE_INSTRUCTIONS[mnemonic] - - # Инструкции с переменным размером — анализируем операнды - if mnemonic in ("загрузить", "сохранить", "загрузить_адрес"): - for op in operands: - if op.startswith('MEM:reg_indirect:'): - return 3 # косвенная: REX + opcode + ModR/M - return 7 # абсолютная: REX + opcode + ModR/M + disp32 - - if mnemonic in ("втолкнуть", "вытолкнуть"): - if operands: - reg = operands[0] - if reg in ('р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'): - return 2 # нужен REX-префикс - return 1 # без REX - - if mnemonic in ("прибавить_непосредственно", "вычесть_непосредственно", "сравнить_с"): - return 7 # пессимистично: REX + opcode + ModR/M + imm32 - - if mnemonic == "переместить_имм": - return 10 # пессимистично: mov reg64, imm64 - - if mnemonic in ("переместить_с_нулями", "переместить_со_знаком"): - return 8 # REX + 3-байтный opcode + ModR/M + disp32 - - if mnemonic == "загрузить_байт": - return 2 # opcode + imm8 - - if mnemonic == "втолкнуть_непосредственно": - return 5 # пессимистично: opcode + imm32 - - # Неизвестная инструкция - if PESSIMISTIC_SIZE_ESTIMATE: - return 10 - else: - return 3 - - def calculate_layout(self): - text_size = self.position[".text"] - data_size = self.position[".data"] - bnd_size = self.position[".бнд"] - - elf_header_size = 64 - ph_size = 56 - ph_num = 3 - ph_table_size = ph_num * ph_size - - offset_text = align_up(elf_header_size + ph_table_size, PAGE_SIZE) - offset_data = align_up(offset_text + text_size, PAGE_SIZE) - vaddr_text = text_vaddr_base - vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE) - vaddr_bnd = vaddr_data + PAGE_SIZE - - comment_size = len("Сборщик КВС".encode('utf-8')) + 1 - offset_comment = align_up(offset_data + data_size, 1) - - 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" - shstrtab_size = len(shstrtab_content) - shstrtab_offset = align_up(offset_comment + comment_size, 8) - shdr_offset = align_up(shstrtab_offset + shstrtab_size, 16) - - return { - "text_size": text_size, - "data_size": data_size, - "bnd_size": bnd_size, - "offset_text": offset_text, - "offset_data": offset_data, - "vaddr_text": vaddr_text, - "vaddr_data": vaddr_data, - "vaddr_bnd": vaddr_bnd, - "offset_comment": offset_comment, - "comment_size": comment_size, - "shstrtab_offset": shstrtab_offset, - "shstrtab_size": shstrtab_size, - "shdr_offset": shdr_offset, - "entry_point": self.entry_point, - } + for segment, addr, byte, target, source, label, source_with_values, calc_target, calc_byte in entries: + writer.writerow([ + segment, + f"0x{addr:08x}", + f"0x{byte:02x}", + label, + target, + source, + source_with_values, + calc_target, + calc_byte + ]) -def write_pass1(pass1_data, labels, label_sections, symbols, output_file): - with open(output_file, 'w', encoding='utf-8') as f: - for key, value in pass1_data.items(): - f.write(f"PARAM:{key}:{value}\n") - for label, pos in labels.items(): - sec = label_sections.get(label, ".text") - f.write(f"LABEL:{label}:{sec}:{pos}\n") - for name, value in symbols.items(): - f.write(f"SYMBOL:{name}:{value}\n") -if __name__ == "__main__": +def main(): if len(sys.argv) != 3: - print("Использование: python kvs_pass1.py <вход.аст> <выход.проход1>") + print("Использование: python kvs_pass1.py <вход.аст> <выход.csv>") sys.exit(1) - ast_lines = read_ast(sys.argv[1]) - pass1 = Pass1() + ast_file = sys.argv[1] + csv_file = sys.argv[2] + + reset_state() + + set_segment('.header') + generate_elf_header() + generate_program_headers() + align_to(PAGE_SIZE) + + ast_lines = read_ast(ast_file) for line in ast_lines: - pass1.process_line(line) + process_ast_line(line) - layout = pass1.calculate_layout() - write_pass1(layout, pass1.labels, pass1.label_sections, pass1.symbols, sys.argv[2]) + finalize_headers() + save_to_csv(csv_file) - print(f"Проход 1 (режим: {'пессимистичный' if PESSIMISTIC_SIZE_ESTIMATE else 'оптимистичный'}):") - print(f" .text: размер={layout['text_size']} байт, смещение_в_файле=0x{layout['offset_text']:x}, виртуальный_адрес=0x{layout['vaddr_text']:x}") - print(f" .data: размер={layout['data_size']} байт, смещение_в_файле=0x{layout['offset_data']:x}, виртуальный_адрес=0x{layout['vaddr_data']:x}") - print(f" .бнд: размер={layout['bnd_size']} байт, виртуальный_адрес=0x{layout['vaddr_bnd']:x}") - print(f" entry_point: {layout['entry_point']}") - print(f" метки:") - for label, pos in pass1.labels.items(): - sec = pass1.label_sections.get(label, ".text") - if sec == ".text": - addr = layout['vaddr_text'] + pos - elif sec == ".data": - addr = layout['vaddr_data'] + pos - elif sec == ".бнд": - addr = layout['vaddr_bnd'] + pos - else: - addr = pos - print(f" {label}: секция={sec}, смещение={pos}, адрес=0x{addr:x}") \ No newline at end of file + vaddr_data_final = align_up(vaddr_text + len(text_buffer), PAGE_SIZE) + vaddr_bnd_final = align_up(vaddr_data_final + len(data_buffer), PAGE_SIZE) + + print(f"\n=== Первый проход (однопроходная генерация с заглушками) ===") + print(f" .text: {len(text_buffer)} байт, виртуальный адрес=0x{vaddr_text:x}") + print(f" .data: {len(data_buffer)} байт, виртуальный адрес=0x{vaddr_data_final:x}") + print(f" .bnd: {bnd_size} байт, виртуальный адрес=0x{vaddr_bnd_final:x}") + print(f" точка входа: {entry_point} = 0x{labels.get(entry_point, vaddr_text):x}") + print(f" меток: {len(labels)}") + print(f" констант: {len(symbols)}") + print(f" релокаций: {len(relocations)}") + print(f" записей в CSV: {len(entries)}") + print(f" CSV сохранен: {csv_file}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/kvs_pass2.py b/kvs_pass2.py index 9071b44..c06e1c9 100644 --- a/kvs_pass2.py +++ b/kvs_pass2.py @@ -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}") \ No newline at end of file + main() \ No newline at end of file diff --git a/kvs_pass3.py b/kvs_pass3.py new file mode 100644 index 0000000..44f148e --- /dev/null +++ b/kvs_pass3.py @@ -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() \ No newline at end of file diff --git a/kvs_pass4.py b/kvs_pass4.py new file mode 100644 index 0000000..39d891e --- /dev/null +++ b/kvs_pass4.py @@ -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() \ No newline at end of file diff --git a/kvs_verify.py b/kvs_verify.py deleted file mode 100644 index 4f4f813..0000000 --- a/kvs_verify.py +++ /dev/null @@ -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) \ No newline at end of file diff --git a/инструменты/kvs_csv_builder.py b/инструменты/kvs_csv_builder.py new file mode 100644 index 0000000..08c983f --- /dev/null +++ b/инструменты/kvs_csv_builder.py @@ -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 ") + sys.exit(1) + + generate_empty_program() + save_to_csv(sys.argv[1]) + print("\nГотово!", file=sys.stderr) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/тесты/bss_bug.txt b/тесты/bss_bug.txt deleted file mode 100644 index 0a39a2b..0000000 --- a/тесты/bss_bug.txt +++ /dev/null @@ -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` для меток `.бнд`. \ No newline at end of file diff --git a/тесты/bss_bug.квс b/тесты/bss_bug.квс deleted file mode 100644 index e581119..0000000 --- a/тесты/bss_bug.квс +++ /dev/null @@ -1,53 +0,0 @@ -.текст -.глобал _start - -_start: - ; ============================================= - ; ТЕСТ 1: Абсолютная адресация в .data - ; ============================================= - переместить_имм раикс, 0x42 - сохранить [абс_данные], раикс - - ; ============================================= - ; ТЕСТ 2: Косвенная адресация в .data - ; ============================================= - переместить_имм рбикс, косв_данные - переместить_имм раикс, 0x99 - сохранить [рбикс], раикс - - ; ============================================= - ; ТЕСТ 3: Косвенная адресация в .бнд - ; ============================================= - переместить_имм рсикс, неиниц_бнд - переместить_имм раикс, 0x77 - сохранить [рсикс], раикс - - ; ============================================= - ; Читаем всё обратно и проверяем - ; ============================================= - - ; Читаем абсолютную из .data - загрузить р8, [абс_данные] - - ; Читаем косвенную из .data - загрузить р9, [рбикс] - - ; Читаем косвенную из .бнд - загрузить р10, [рсикс] - - ; ============================================= - ; ЗАВЕРШЕНИЕ: возвращаем значение из абсолютной .data - ; ============================================= - загрузить рдиай, [абс_данные] - переместить_имм раикс, 60 - вызов_системы - -.данные -абс_данные: - .байт 0 -косв_данные: - .байт 0 - -.бнд -неиниц_бнд: - .резб 8 \ No newline at end of file diff --git a/тесты/itoa0.квс b/тесты/itoa0.квс deleted file mode 100644 index 1cf1b8b..0000000 --- a/тесты/itoa0.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/itoa1.квс b/тесты/itoa1.квс deleted file mode 100644 index 3852ef0..0000000 --- a/тесты/itoa1.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/itoa2.квс b/тесты/itoa2.квс deleted file mode 100644 index 4e98aba..0000000 --- a/тесты/itoa2.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/itoa3.квс b/тесты/itoa3.квс deleted file mode 100644 index af76610..0000000 --- a/тесты/itoa3.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/t1.py b/тесты/t1.py deleted file mode 100644 index 69027e8..0000000 --- a/тесты/t1.py +++ /dev/null @@ -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() \ No newline at end of file diff --git a/тесты/test_bss.квс b/тесты/test_bss.квс deleted file mode 100644 index dc0e7e0..0000000 --- a/тесты/test_bss.квс +++ /dev/null @@ -1,9 +0,0 @@ -.текст -.глобал _start -_start: - переместить_имм раикс, 60 - переместить_имм рдиай, 0 - вызов_системы - -.бнд -буфер: .резб 1048576 ; 1 МБ = 1024 * 1024 \ No newline at end of file diff --git a/тесты/test_bss_only.квс b/тесты/test_bss_only.квс deleted file mode 100644 index 5737c6d..0000000 --- a/тесты/test_bss_only.квс +++ /dev/null @@ -1,45 +0,0 @@ -.текст -.глобал _start - -_start: - ; ============================================= - ; ТЕСТ 1: Абсолютная адресация в .бнд - ; ============================================= - переместить_имм раикс, 0x42 - сохранить [абс_перем], раикс - - ; ============================================= - ; ТЕСТ 2: Косвенная адресация в .бнд - ; ============================================= - переместить_имм рбикс, косв_перем - переместить_имм раикс, 0x99 - сохранить [рбикс], раикс - - ; ============================================= - ; ТЕСТ 3: Ещё одна косвенная адресация в .бнд - ; ============================================= - переместить_имм рсикс, ещё_перем - переместить_имм раикс, 0x77 - сохранить [рсикс], раикс - - ; ============================================= - ; Читаем всё обратно - ; ============================================= - загрузить р8, [абс_перем] - загрузить р9, [рбикс] - загрузить р10, [рсикс] - - ; ============================================= - ; ЗАВЕРШЕНИЕ: возвращаем из абс_перем - ; ============================================= - загрузить рдиай, [абс_перем] - переместить_имм раикс, 60 - вызов_системы - -.бнд -абс_перем: - .резб 1 -косв_перем: - .резб 1 -ещё_перем: - .резб 8 \ No newline at end of file diff --git a/тесты/test_label.квс b/тесты/test_label.квс deleted file mode 100644 index 08508af..0000000 --- a/тесты/test_label.квс +++ /dev/null @@ -1,15 +0,0 @@ -.текст -.глобал _start - -_start: - ; Запись значения 42 в переменную по метке - переместить_имм раикс, 42 - сохранить [переменная], раикс - - ; Завершение с кодом 42 - переместить_имм раикс, 60 - загрузить рдиай, [переменная] - вызов_системы - -.данные -переменная: .байт 0 \ No newline at end of file diff --git a/тесты/test_minimal.квс b/тесты/test_minimal.квс deleted file mode 100644 index 28f6866..0000000 --- a/тесты/test_minimal.квс +++ /dev/null @@ -1,15 +0,0 @@ -.текст -.глобал _start - -_start: - ; Запись значения 42 в переменную по адресу 0x402000 - переместить_имм раикс, 42 - сохранить [0x402000], раикс - - ; Завершение с кодом 42 (читаем из переменной) - переместить_имм раикс, 60 - загрузить рдиай, [0x402000] - вызов_системы - -.данные -тестовая_переменная: .байт 0 \ No newline at end of file diff --git a/тесты/test_minimal2.квс b/тесты/test_minimal2.квс deleted file mode 100644 index 5f9e0fd..0000000 --- a/тесты/test_minimal2.квс +++ /dev/null @@ -1,34 +0,0 @@ -.текст -.глобал _start - -_start: - ; === ТЕСТ 1: Запись через косвенную адресацию === - ; Загружаем адрес переменной в регистр - переместить_имм рбикс, тестовая_переменная - - ; Записываем 42 через косвенную адресацию [рбикс] - переместить_имм раикс, 42 - сохранить [рбикс], раикс - - ; === ТЕСТ 2: Чтение через косвенную адресацию === - ; Загружаем адрес другой переменной в регистр - переместить_имм рсикс, вторая_переменная - - ; Читаем через косвенную адресацию [рсикс] - загрузить рдикс, [рсикс] - - ; === ТЕСТ 3: Проверяем, что записалось === - ; Читаем первую переменную через косвенную - загрузить рсикс, [рбикс] - - ; === ЗАВЕРШЕНИЕ === - ; Выходим с кодом из первой переменной (должно быть 42) - переместить_имм раикс, 60 - переместить рдиай, рсикс - вызов_системы - -.данные -тестовая_переменная: - .байт 0 -вторая_переменная: - .байт 99 \ No newline at end of file diff --git a/тесты/test_minimal3.квс b/тесты/test_minimal3.квс deleted file mode 100644 index 2f381d6..0000000 --- a/тесты/test_minimal3.квс +++ /dev/null @@ -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 байт под указатель на строку \ No newline at end of file diff --git a/тесты/test_success.квс b/тесты/test_success.квс deleted file mode 100644 index 2fbcc36..0000000 --- a/тесты/test_success.квс +++ /dev/null @@ -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 изобретать (или кучу?) \ No newline at end of file diff --git a/тесты/test_success2.квс b/тесты/test_success2.квс deleted file mode 100644 index e462120..0000000 --- a/тесты/test_success2.квс +++ /dev/null @@ -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) \ No newline at end of file diff --git a/тесты/test_success3.квс b/тесты/test_success3.квс deleted file mode 100644 index c778c0e..0000000 --- a/тесты/test_success3.квс +++ /dev/null @@ -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 байт под указатель на строку \ No newline at end of file diff --git a/тесты/длин_тест9.квс b/тесты/длин_тест9.квс deleted file mode 100644 index 80c861b..0000000 --- a/тесты/длин_тест9.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/длина_числа.квс b/тесты/длина_числа.квс deleted file mode 100644 index 4a19126..0000000 --- a/тесты/длина_числа.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/привет_disasm.txt b/тесты/привет_disasm.txt deleted file mode 100644 index 1f20ced..0000000 --- a/тесты/привет_disasm.txt +++ /dev/null @@ -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 diff --git a/тесты/сложный_тест9.квс b/тесты/сложный_тест9.квс deleted file mode 100644 index a029e43..0000000 --- a/тесты/сложный_тест9.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/т1.квс b/тесты/т1.квс deleted file mode 100644 index 250e4fe..0000000 --- a/тесты/т1.квс +++ /dev/null @@ -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 - вызов_системы diff --git a/тесты/т1_.квс b/тесты/т1_.квс deleted file mode 100644 index ddaaaba..0000000 --- a/тесты/т1_.квс +++ /dev/null @@ -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 - вызов_системы \ No newline at end of file diff --git a/тесты/циклы.квс b/тесты/циклы.квс deleted file mode 100644 index 5c08285..0000000 --- a/тесты/циклы.квс +++ /dev/null @@ -1,27 +0,0 @@ -.текст -.глобал _start - -_start: - ; Счётчик циклов = 5 - переместить_имм р8, 5 - -цикл: - ; Выводим сообщение - переместить_имм раикс, 1 - переместить_имм рдиай, 1 - переместить_имм рсиай, msg - переместить_имм рдикс, 21 - вызов_системы - - ; Счётчик-- - уменьшить р8 - сравнить_с р8, 0 - короткий_переход_если_неравно цикл - - ; exit(0) - переместить_имм раикс, 60 - переместить_имм рдиай, 0 - вызов_системы - -.данные -msg: .строка "Привет мир!\n" \ No newline at end of file diff --git a/тесты/циклы2.квс b/тесты/циклы2.квс deleted file mode 100644 index d701bb4..0000000 --- a/тесты/циклы2.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/циклы3.квс b/тесты/циклы3.квс deleted file mode 100644 index cdb9d2a..0000000 --- a/тесты/циклы3.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/циклы4.квс b/тесты/циклы4.квс deleted file mode 100644 index 05ad7bd..0000000 --- a/тесты/циклы4.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/циклы5.квс b/тесты/циклы5.квс deleted file mode 100644 index 2f914eb..0000000 --- a/тесты/циклы5.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/циклы6.квс b/тесты/циклы6.квс deleted file mode 100644 index 37c16ab..0000000 --- a/тесты/циклы6.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/циклы7.квс b/тесты/циклы7.квс deleted file mode 100644 index e3a5294..0000000 --- a/тесты/циклы7.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/циклы8.квс b/тесты/циклы8.квс deleted file mode 100644 index ff1b420..0000000 --- a/тесты/циклы8.квс +++ /dev/null @@ -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 \ No newline at end of file diff --git a/тесты/циклы9.квс b/тесты/циклы9.квс deleted file mode 100644 index 3659e32..0000000 --- a/тесты/циклы9.квс +++ /dev/null @@ -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 \ No newline at end of file