From 7f33ec8dc24f6d42e16345549664ce7cb37285dc Mon Sep 17 00:00:00 2001 From: artradeskz Date: Sat, 8 Nov 2025 13:24:11 +0300 Subject: [PATCH] Add files via upload --- short_jumps/csvhtml.py | 160 ++++ short_jumps/disassembler_skip_zero2.py | 149 ++++ short_jumps/kvs_5.py | 653 ++++++++++++++ short_jumps/kvs_6.py | 930 ++++++++++++++++++++ short_jumps/дебаг.квс | 33 + short_jumps/привеет.квс | 35 + short_jumps/сложный_тест0.квс | 53 ++ short_jumps/сложный_тест1.квс | 131 +++ short_jumps/сложный_тест2.квс | 93 ++ short_jumps/сложный_тест3.квс | 114 +++ short_jumps/сложный_тест4.квс | 137 +++ short_jumps/сложный_тест5.квс | 157 ++++ short_jumps/сложный_тест6.квс | 180 ++++ short_jumps/сложный_тест7.квс | 200 +++++ short_jumps/сложный_тест8.квс | 217 +++++ short_jumps/сложный_тест9.квс | 204 +++++ short_jumps/шорт_тест.квс | 237 +++++ 17 files changed, 3683 insertions(+) create mode 100644 short_jumps/csvhtml.py create mode 100644 short_jumps/disassembler_skip_zero2.py create mode 100644 short_jumps/kvs_5.py create mode 100644 short_jumps/kvs_6.py create mode 100644 short_jumps/дебаг.квс create mode 100644 short_jumps/привеет.квс create mode 100644 short_jumps/сложный_тест0.квс create mode 100644 short_jumps/сложный_тест1.квс create mode 100644 short_jumps/сложный_тест2.квс create mode 100644 short_jumps/сложный_тест3.квс create mode 100644 short_jumps/сложный_тест4.квс create mode 100644 short_jumps/сложный_тест5.квс create mode 100644 short_jumps/сложный_тест6.квс create mode 100644 short_jumps/сложный_тест7.квс create mode 100644 short_jumps/сложный_тест8.квс create mode 100644 short_jumps/сложный_тест9.квс create mode 100644 short_jumps/шорт_тест.квс diff --git a/short_jumps/csvhtml.py b/short_jumps/csvhtml.py new file mode 100644 index 0000000..15873fe --- /dev/null +++ b/short_jumps/csvhtml.py @@ -0,0 +1,160 @@ +import tkinter as tk +from tkinter import filedialog, messagebox +import csv +import os + +# --- Основная функция конвертации --- +def convert_csv_to_html(csv_file_path, html_file_path): + """ + Читает semicolon-separated CSV файл и создает красивую HTML-страницу. + Возвращает (True, сообщение) в случае успеха или (False, сообщение) в случае ошибки. + """ + try: + with open(csv_file_path, 'r', encoding='utf-8') as f: + reader = csv.DictReader(f, delimiter=';') + headers = reader.fieldnames + if not headers: + return False, "CSV-файл пуст или не имеет заголовков." + + rows = list(reader) + + except FileNotFoundError: + return False, f"Файл не найден: {csv_file_path}" + except Exception as e: + return False, f"Ошибка при чтении CSV: {e}" + + # CSS для красивого оформления + css_style = """ + + """ + + # Начало HTML-документа + html_content = f""" + + + + + + {os.path.basename(html_file_path)} + {css_style} + + +
+

Анализ дизассемблерного листинга: {os.path.basename(csv_file_path)}

+ + + """ + for header in headers: + html_content += f"\n" + + html_content += "\n" + + # Добавляем строки таблицы + for row in rows: + address = row.get('адрес', '').strip() + target_address = row.get('целевой_адрес', '').strip() + + link_html = target_address + if target_address: + link_html = f'{target_address}' + + # Присваиваем id каждой строке на основе ее адреса + row_id = address if address else '' + + html_content += f'\n' + html_content += f'\n' + html_content += f'\n' + html_content += f'\n' + html_content += f'\n' + html_content += "\n" + + html_content += "
{header}
{address}{row.get("байт", "")}{link_html}{row.get("исходная_команда", "")}
" + + # Запись HTML в файл + try: + with open(html_file_path, 'w', encoding='utf-8') as f: + f.write(html_content) + return True, f"Успешно! Файл сохранен как:\n{html_file_path}" + except Exception as e: + return False, f"Ошибка при записи HTML файла: {e}" + + +# --- Функция-обработчик нажатия на кнопку --- +def open_file_and_convert(): + # Открываем диалог выбора файла + file_path = filedialog.askopenfilename( + title="Выберите CSV-файл для конвертации", + filetypes=(("CSV файлы", "*.csv"), ("Все файлы", "*.*")) + ) + + # Если пользователь не выбрал файл, выходим + if not file_path: + status_label.config(text="Операция отменена.") + return + + # Формируем имя для выходного HTML-файла + base_name = os.path.splitext(file_path)[0] + output_path = f"{base_name}.html" + + # Обновляем статус + status_label.config(text="Обработка файла...") + root.update_idletasks() # Принудительно обновляем интерфейс + + # Вызываем функцию конвертации + success, message = convert_csv_to_html(file_path, output_path) + + # Показываем результат + if success: + status_label.config(text="Готово!") + messagebox.showinfo("Успех", message) + else: + status_label.config(text="Произошла ошибка.") + messagebox.showerror("Ошибка", message) + + +# --- Создание графического интерфейса --- +root = tk.Tk() +root.title("CSV в HTML Конвертер") +root.geometry("450x200") # Размер окна +root.resizable(False, False) # Запрещаем изменять размер + +# Создаем фрейм для лучшего расположения элементов +main_frame = tk.Frame(root, padx=20, pady=20) +main_frame.pack(expand=True, fill=tk.BOTH) + +# Кнопка "Открыть" +open_button = tk.Button( + main_frame, + text="Открыть CSV-файл", + command=open_file_and_convert, + width=20, + height=2, + font=("Helvetica", 12) +) +open_button.pack(pady=10) + +# Метка для отображения статуса +status_label = tk.Label( + main_frame, + text="Нажмите кнопку, чтобы выбрать файл", + wraplength=400, # Перенос длинных строк + justify=tk.CENTER +) +status_label.pack(pady=10) + +# Запускаем главный цикл приложения +root.mainloop() \ No newline at end of file diff --git a/short_jumps/disassembler_skip_zero2.py b/short_jumps/disassembler_skip_zero2.py new file mode 100644 index 0000000..4284ad6 --- /dev/null +++ b/short_jumps/disassembler_skip_zero2.py @@ -0,0 +1,149 @@ +import tkinter as tk +from tkinter import filedialog, messagebox +import os +import subprocess +from datetime import datetime + +def binary_to_disasm(input_file, output_file=None, skip_zeros=True): + """Конвертирует бинарный файл в дизассемблированный код с помощью ndisasm.""" + try: + # Если выходной файл не указан, создаём рядом с оригиналом + if not output_file: + base_name = os.path.splitext(input_file)[0] + output_file = f"{base_name}_disasm.txt" + + # Вызываем ndisasm для дизассемблирования + result = subprocess.run( + ['ndisasm', '-b64', input_file], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + + # Проверяем наличие ошибок от ndisasm + if result.returncode != 0: + error_msg = result.stderr.strip() + return False, f"Ошибка ndisasm: {error_msg}" + + # Получаем текущую дату и время + current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # Фильтруем строки в зависимости от настройки + lines = result.stdout.splitlines() + if skip_zeros: + filtered_lines = [line for line in lines if 'add [rax],al' not in line] + filter_status = "Нули (add [rax],al) пропущены" + else: + filtered_lines = lines + filter_status = "Нули (add [rax],al) не пропущены" + + # Записываем отфильтрованные строки в файл с заголовком + with open(output_file, 'w', encoding='utf-8') as out_file: + # Добавляем заголовок с информацией + out_file.write("=" * 60 + "\n") + out_file.write(f"Дизассемблированный код сгенерирован с помощью ndisasm\n") + out_file.write(f"Исходный файл: {os.path.basename(input_file)}\n") + out_file.write(f"Дата создания: {current_time}\n") + out_file.write(f"Статус фильтра: {filter_status}\n") + out_file.write("=" * 60 + "\n\n") + + for line in filtered_lines: + out_file.write(line + '\n') + + return True, output_file + + except FileNotFoundError: + return False, "ndisasm не найден. Убедитесь, что NASM установлен и доступен в PATH" + except Exception as e: + return False, str(e) + +def select_and_convert(): + """Открывает диалог выбора файла и конвертирует""" + input_file = filedialog.askopenfilename( + title="Выберите бинарный файл", + filetypes=(("Бинарные файлы", "*.bin *.elf *.o"), ("Все файлы", "*.*")) + ) + + if not input_file: + return + + # Получаем состояние галочки + skip_zeros = skip_zeros_var.get() + + success, result = binary_to_disasm(input_file, skip_zeros=skip_zeros) + + if success: + messagebox.showinfo( + "Готово", + f"Файл успешно дизассемблирован!\n" + f"Пропуск нулей: {'ВКЛ' if skip_zeros else 'ВЫКЛ'}\n" + f"Результат сохранён как:\n{result}" + ) + else: + messagebox.showerror( + "Ошибка", + f"Не удалось дизассемблировать файл:\n{result}" + ) + +def main(): + """Создаём графический интерфейс""" + global skip_zeros_var + + root = tk.Tk() + root.title("Дизассемблер бинарных файлов") + root.geometry("500x250") + + # Центрируем окно + root.eval('tk::PlaceWindow . center') + + # Переменная для хранения состояния галочки + skip_zeros_var = tk.BooleanVar(value=True) # По умолчанию включено + + # Создаём элементы интерфейса + label = tk.Label( + root, + text="Дизассемблер бинарных файлов (ndisasm)", + font=('Arial', 14), + pady=20 + ) + label.pack() + + # Фрейм для галочки + checkbox_frame = tk.Frame(root) + checkbox_frame.pack(pady=10) + + # Галочка для пропуска нулей + skip_zeros_check = tk.Checkbutton( + checkbox_frame, + text="Пропускать нули (add [rax],al)", + variable=skip_zeros_var, + font=('Arial', 10) + ) + skip_zeros_check.pack() + + # Кнопка конвертации + btn_convert = tk.Button( + root, + text="Выбрать файл и дизассемблировать", + command=select_and_convert, + font=('Arial', 12), + padx=20, + pady=10 + ) + btn_convert.pack(pady=10) + + # Кнопка выхода + btn_exit = tk.Button( + root, + text="Выход", + command=root.quit, + font=('Arial', 10), + padx=20, + pady=5 + ) + btn_exit.pack(pady=10) + + root.mainloop() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/short_jumps/kvs_5.py b/short_jumps/kvs_5.py new file mode 100644 index 0000000..037adb0 --- /dev/null +++ b/short_jumps/kvs_5.py @@ -0,0 +1,653 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +kvs_5.py +КВС - язык программирования +без использования re +(расширенная версия с короткими переходами и полными регистрами) +""" + +import sys +import struct + +# Глобальная переменная для имени исходного файла +source_filename = "" + +def safe_close(f): + if f is not None: + f.close() + +# === Глобальные данные === +INSTRUCTIONS = { + "переместить_имм": {"code": None, "type": "reg_imm"}, + "сравнить_с": {"code": None, "type": "cmp_reg_imm"}, + "переход_если_неравно": {"code": b"\x0F\x85", "type": "jcc"}, + "вызов_системы": {"code": b"\x0F\x05", "type": "none"}, + "переход": {"code": b"\xE9", "type": "jmp"}, + # === Короткие переходы (добавлено) === + "короткий_переход": {"code": b"\xEB", "type": "short_jmp"}, + "короткий_переход_если_равно" : {"code": b"\x74", "type": "short_jcc"}, + "короткий_переход_если_неравно" : {"code": b"\x75", "type": "short_jcc"}, + "короткий_переход_если_меньше" : {"code": b"\x7C", "type": "short_jcc"}, + "короткий_переход_если_больше" : {"code": b"\x7F", "type": "short_jcc"}, + "короткий_переход_если_меньше_или_равно": {"code": b"\x7E", "type": "short_jcc"}, + "короткий_переход_если_больше_или_равно": {"code": b"\x7D", "type": "short_jcc"}, + "короткий_переход_если_перенос" : {"code": b"\x72", "type": "short_jcc"}, + "короткий_переход_если_нет_переноса" : {"code": b"\x73", "type": "short_jcc"}, + "короткий_переход_если_ноль" : {"code": b"\x74", "type": "short_jcc"}, + "короткий_переход_если_не_ноль" : {"code": b"\x75", "type": "short_jcc"}, +} + +REGISTERS = { + # 64-битные + "раикс": 0, "рсикс": 1, "рдикс": 2, "рбикс": 3, + "рсипи": 4, "рбипи": 5, "рсиай": 6, "рдиай": 7, + "р8": 8, "р9": 9, "р10": 10, "р11": 11, + "р12": 12, "р13": 13, "р14": 14, "р15": 15, + # 32-битные + "еаикс": 0, "есикс": 1, "едикс": 2, "ебикс": 3, + "есипи": 4, "ебипи": 5, "есиай": 6, "едиай": 7, + "р8д": 8, "р9д": 9, "р10д": 10, "р11д": 11, + "р12д": 12, "р13д": 13, "р14д": 14, "р15д": 15, + # 16-битные + "аикс": 0, "сикс": 1, "дикс": 2, "бикс": 3, + "эсп": 4, "бипи": 5, "эс": 6, "ди": 7, + "р8в": 8, "р9в": 9, "р10в": 10, "р11в": 11, + "р12в": 12, "р13в": 13, "р14в": 14, "р15в": 15, + # 8-битные младшие + "ал": 0, "кл": 1, "дл": 2, "бл": 3, + "спл": 4, "бпл": 5, "сил": 6, "дил": 7, + "р8б": 8, "р9б": 9, "р10б": 10, "р11б": 11, + "р12б": 12, "р13б": 13, "р14б": 14, "р15б": 15, + # 8-битные старшие (только первые 4) + "аш": 0, "чш": 1, "дш": 2, "бш": 3, +} + +# Глобальное состояние ассемблера +labels = {} +label_sections = {} +symbols = {} +sections = {".text": bytearray(), ".data": bytearray()} +current_section = ".text" +entry_point = "_start" +position = {".text": 0, ".data": 0} +pass_num = 0 + +# === Для логирования === +log_entries = [] + +# === ELF layout === +PAGE_SIZE = 0x1000 +elf_base_vaddr = 0x400000 +text_vaddr_base = 0x401000 +data_vaddr_base = 0x402000 + +text_size = 0 +data_size = 0 +comment_size = 0 +offset_text = 0 +offset_data = 0 +offset_comment = 0 +shstrtab_offset = 0 +shdr_offset = 0 +vaddr_text = 0 +vaddr_data = 0 + +def align_up(x, align): + return (x + align - 1) & ~(align - 1) + +def get_reg_info(reg_name): + if reg_name in ["аш", "чш", "дш", "бш"]: + return {"size": 8, "index": REGISTERS[reg_name], "high8": True} + elif reg_name.endswith(("б", "л")) or reg_name in ["ал", "кл", "дл", "бл", "спл", "бпл", "сил", "дил"]: + return {"size": 8, "index": REGISTERS[reg_name], "high8": False} + elif reg_name.endswith("в") or reg_name in ["аикс", "сикс", "дикс", "бикс", "эсп", "бипи", "эс", "ди"]: + return {"size": 16, "index": REGISTERS[reg_name]} + elif reg_name.endswith("д") or reg_name in ["еаикс", "есикс", "едикс", "ебикс", "есипи", "ебипи", "есиай", "едиай"]: + return {"size": 32, "index": REGISTERS[reg_name]} + else: + return {"size": 64, "index": REGISTERS[reg_name]} + +# === Функции формирования ошибок === +def make_error_msg(line_num, line_text, detail): + return "Ошибка в файле " + source_filename + ", строка " + str(line_num) + ":\n " + line_text + "\n" + detail + +def error_invalid_operand_count(mnemonic, expected, got): + return "Инструкция '" + mnemonic + "':\n ожидается " + str(expected) + " операнд(а/ов), получено: " + str(got) + +def error_unknown_mnemonic(mnemonic): + return "Неизвестная инструкция: '" + mnemonic + "'" + +def error_invalid_register(op_name, reg_name, mnemonic): + return ("Инструкция '" + mnemonic + "':\n операнд '" + op_name + "' = '" + reg_name + + "' не является допустимым регистром.\n Допустимые регистры: " + ", ".join(list(REGISTERS.keys()))) + +def error_invalid_number_format(s): + return "Недопустимый формат числа: '" + s + "'" + +def error_unknown_directive(word): + return "Неизвестная директива: '" + word + "'" + +def error_missing_label(label): + return "Метка не найдена: '" + label + "'" + +def error_unexpected_string_in_byte(): + return ".байт требует числовые значения, не строки" + +def error_unterminated_string(): + return "Незакрытая кавычка в строке" + +# === Лексер === +def tokenize_line(line): + semi = line.find(';') + if semi != -1: + line = line[:semi] + line = line.rstrip() + if not line: + return [] + tokens = [] + i = 0 + n = len(line) + while i < n: + ch = line[i] + if ch.isspace(): + i += 1 + continue + if ch == '"': + i += 1 + s = '' + while i < n and line[i] != '"': + if line[i] == '\\' and i + 1 < n: + i += 1 + esc = line[i] + if esc == 'n': + s += '\n' + elif esc == 't': + s += '\t' + elif esc == '"': + s += '"' + elif esc == '\\': + s += '\\' + else: + s += '\\' + esc + i += 1 + else: + s += line[i] + i += 1 + if i >= n: + raise ValueError(error_unterminated_string()) + i += 1 + tokens.append(('string', s)) + continue + if ch == ',': + tokens.append(('comma', ',')) + i += 1 + continue + if ch == ':': + tokens.append(('colon', ':')) + i += 1 + continue + j = i + while j < n and not (line[j].isspace() or line[j] in ',:;'): + j += 1 + word = line[i:j] + if word: + tokens.append(('word', word)) + i = j + return tokens + +# === Парсинг === +def parse_operand(operand): + if operand.isdigit(): + return int(operand) + if operand.startswith("0x"): + return int(operand, 16) + if operand in labels: + section = label_sections[operand] + if pass_num == 2: + base = vaddr_text if section == ".text" else vaddr_data + return labels[operand] + base + else: + return labels[operand] + if operand in symbols: + return symbols[operand] + raise ValueError("Неизвестный операнд: " + operand) + +def encode_instruction(mnemonic, operands, line_num, line_text): + instr = INSTRUCTIONS[mnemonic] + code = bytearray() + itype = instr["type"] + + if itype == "none": + code.extend(instr["code"]) + + elif itype == "reg_imm": + if len(operands) != 2: + raise ValueError(error_invalid_operand_count(mnemonic, 2, len(operands))) + reg_info = get_reg_info(operands[0]) + if reg_info is None: + raise ValueError(error_invalid_register("назначения", operands[0], mnemonic)) + reg = reg_info["index"] + imm = parse_operand(operands[1]) + + if 0 <= reg <= 7: + code.extend(b'\x48') + code.append(0xB8 + reg) + code.extend(struct.pack('= 8: + rex |= 0x01 + code.append(rex) + code.append(0x81) + modrm = 0xF8 | (reg & 7) + code.append(modrm) + code.extend(struct.pack(' 0x7FFFFFFF: + raise ValueError("Цель слишком далеко для 32-битного смещения в инструкции '" + mnemonic + "': " + str(offset)) + code.extend(struct.pack(' 0x7FFFFFFF: + raise ValueError("Цель условного перехода слишком далеко: " + str(offset)) + code.extend(struct.pack(' 127: + raise ValueError("Цель слишком далеко для короткого перехода: " + str(offset)) + code.append(0xEB) + code.append(offset & 0xFF) + + elif itype == "short_jcc": + if len(operands) != 1: + raise ValueError(error_invalid_operand_count(mnemonic, 1, len(operands))) + code.extend(instr["code"]) + target = parse_operand(operands[0]) + current_addr = vaddr_text + position[".text"] + offset = target - (current_addr + 2) + if offset < -128 or offset > 127: + raise ValueError("Цель слишком далеко для короткого условного перехода: " + str(offset)) + code.append(offset & 0xFF) + + else: + raise ValueError("Неизвестный тип инструкции: " + itype) + + return bytes(code) + +def parse_instruction_or_directive(tokens, line_num, line_text): + global current_section, entry_point + first = tokens[0] + if first[0] != 'word': + raise ValueError("Ожидалось слово, получено: " + str(first)) + word = first[1] + if word.startswith('.'): + if word == '.текст': + current_section = ".text" + elif word == '.данные': + current_section = ".data" + elif word == '.глобал': + if len(tokens) < 2 or tokens[1][0] != 'word': + raise ValueError(".глобал требует имя метки") + entry_point = tokens[1][1] + elif word == '.строка_нуль' or word == '.строка': + if len(tokens) < 2 or tokens[1][0] != 'string': + raise ValueError(word + " требует строку в кавычках") + if current_section != ".data": + raise ValueError("Строки разрешены только в секции .data") + s = tokens[1][1] + bstring = s.encode('utf-8') + add_null = (word == '.строка_нуль') + size = len(bstring) + (1 if add_null else 0) + if pass_num == 1: + position[".data"] += size + elif pass_num == 2: + sections[".data"] += bstring + if add_null: + sections[".data"] += b'\x00' + position[".data"] += size + else: + raise ValueError(error_unknown_directive(word)) + return + + mnemonic = word + if mnemonic not in INSTRUCTIONS: + raise ValueError(error_unknown_mnemonic(mnemonic)) + + operands = [] + for tok in tokens[1:]: + if tok[0] == 'word': + operands.append(tok[1]) + elif tok[0] == 'comma': + continue + else: + raise ValueError("Недопустимый токен в операндах: " + str(tok)) + + if pass_num == 2: + instr_info = INSTRUCTIONS[mnemonic] + itype = instr_info["type"] + code = encode_instruction(mnemonic, operands, line_num, line_text) + start_pos = position[current_section] + + if current_section == ".text": + start_vaddr = vaddr_text + start_pos + target_addr = "" + try: + if itype in ("jmp", "jcc", "short_jmp", "short_jcc"): + target = parse_operand(operands[0]) + target_addr = hex(target) + elif itype == "reg_imm": + op_str = operands[1] + if op_str in labels: + sec = label_sections[op_str] + addr = labels[op_str] + (vaddr_text if sec == ".text" else vaddr_data) + target_addr = hex(addr) + except Exception: + target_addr = "ошибка" + + original_cmd = line_text.split(';')[0].strip() + for i, byte in enumerate(code): + addr = start_vaddr + i + byte_hex = "{:02X}".format(byte) + cmd_to_log = original_cmd if i == 0 else "" + log_entries.append((hex(addr), byte_hex, target_addr if i == 0 else "", cmd_to_log)) + + sections[current_section] += code + position[current_section] += len(code) + else: + instr_info = INSTRUCTIONS[mnemonic] + itype = instr_info["type"] + size_map = { + "reg_imm": 10, + "cmp_reg_imm": 7, + "jmp": 5, + "jcc": 6, + "none": lambda: len(instr_info["code"]), + "short_jmp": 2, + "short_jcc": 2, + } + if itype in size_map: + sz = size_map[itype] + position[current_section] += sz() if callable(sz) else sz + else: + raise ValueError("Неподдерживаемый тип инструкции при подсчёте размера: " + itype) + +def parse_tokens(tokens, line_num, line_text): + if not tokens: + return + if len(tokens) >= 2 and tokens[0][0] == 'word' and tokens[1][0] == 'colon': + label = tokens[0][1] + labels[label] = position[current_section] + label_sections[label] = current_section + rest = tokens[2:] + if rest: + parse_instruction_or_directive(rest, line_num, line_text) + return + parse_instruction_or_directive(tokens, line_num, line_text) + +def parse(source): + global pass_num, text_size, data_size, comment_size + global offset_text, offset_data, offset_comment, shstrtab_offset, shdr_offset + global vaddr_text, vaddr_data + global sections, position, log_entries + + log_entries = [] + lines = source.split('\n') + + # ПРОХОД 1 + pass_num = 1 + position[".text"] = 0 + position[".data"] = 0 + labels.clear() + label_sections.clear() + + for line_num, line in enumerate(lines, start=1): + original_line = line.rstrip() + try: + tokens = tokenize_line(line) + parse_tokens(tokens, line_num, original_line) + except Exception as e: + error_full = make_error_msg(line_num, original_line, str(e)) + print(error_full, file=sys.stderr) + sys.exit(1) + + text_size_pass1 = position[".text"] + data_size_pass1 = position[".data"] + print("ПРОХОД 1: text_size=" + str(text_size_pass1) + " bytes, data_size=" + str(data_size_pass1) + " bytes") + + # РАЗМЕЩЕНИЕ + 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_pass1, PAGE_SIZE) + vaddr_text = text_vaddr_base + vaddr_data = align_up(vaddr_text + text_size_pass1, PAGE_SIZE) + + comment_content = "Сборщик КВС".encode('utf-8') + b'\x00' + comment_size = len(comment_content) + offset_comment = align_up(offset_data + data_size_pass1, 1) + + 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_size = 64 + shdr_num = 5 + shdr_offset = align_up(shstrtab_offset + shstrtab_size, 16) + + print("РАЗМЕЩЕНИЕ: .text at offset=" + hex(offset_text) + ", .data at offset=" + hex(offset_data)) + print("ВИРТУАЛЬНЫЕ АДРЕСА: .text at " + hex(vaddr_text) + ", .data at " + hex(vaddr_data)) + print("РАССТОЯНИЕ МЕЖДУ СЕКЦИЯМИ: " + hex(vaddr_data - vaddr_text) + " bytes") + + sections[".comment"] = comment_content + + # ПРОХОД 2 + pass_num = 2 + position[".text"] = 0 + position[".data"] = 0 + sections[".text"] = bytearray() + sections[".data"] = bytearray() + + for line_num, line in enumerate(lines, start=1): + original_line = line.rstrip() + try: + tokens = tokenize_line(line) + parse_tokens(tokens, line_num, original_line) + except Exception as e: + error_full = make_error_msg(line_num, original_line, str(e)) + print(error_full, file=sys.stderr) + sys.exit(1) + + text_size_pass2 = len(sections[".text"]) + data_size_pass2 = len(sections[".data"]) + print("ПРОХОД 2: text_size=" + str(text_size_pass2) + " bytes, data_size=" + str(data_size_pass2) + " bytes") + + if text_size_pass1 != text_size_pass2: + print("ПРЕДУПРЕЖДЕНИЕ: Размер .text изменился между проходами: " + str(text_size_pass1) + " -> " + str(text_size_pass2)) + if data_size_pass1 != data_size_pass2: + print("ПРЕДУПРЕЖДЕНИЕ: Размер .data изменился между проходами: " + str(data_size_pass1) + " -> " + str(data_size_pass2)) + + text_size = text_size_pass2 + data_size = data_size_pass2 + +def create_elf(filename): + global sections, entry_point, labels, vaddr_text, vaddr_data + global offset_text, offset_data, offset_comment, shstrtab_offset, shdr_offset + + text = sections[".text"] + data = sections[".data"] + comment = sections[".comment"] + + actual_text_size = len(text) + actual_data_size = len(data) + expected_vaddr_data = align_up(vaddr_text + actual_text_size, PAGE_SIZE) + if vaddr_data != expected_vaddr_data: + print("КОРРЕКЦИЯ: vaddr_data исправлен с " + hex(vaddr_data) + " на " + hex(expected_vaddr_data)) + vaddr_data = expected_vaddr_data + + print("ФАКТИЧЕСКИЕ РАЗМЕРЫ: .text=" + str(actual_text_size) + ", .data=" + str(actual_data_size)) + print("КОНЕЧНЫЕ АДРЕСА: .text ends at " + hex(vaddr_text + actual_text_size) + ", .data starts at " + hex(vaddr_data)) + print("ПРОВЕРКА ПЕРЕКРЫТИЯ: " + ("ПЕРЕКРЫТИЕ!" if (vaddr_text + actual_text_size) > vaddr_data else "OK")) + + entry_addr = vaddr_text + labels.get(entry_point, 0) + + shstrtab_content = b"\x00.text\x00.data\x00.comment\x00.shstrtab\x00" + shstrtab_size = len(shstrtab_content) + + elf_header_size = 64 + ph_size = 56 + ph_num = 3 + shdr_size = 64 + shdr_num = 5 + + 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('") + sys.exit(1) + +source_file = sys.argv[1] +source_filename = source_file +if not source_file.endswith('.квс'): + print("Ошибка: файл должен иметь расширение .квс") + sys.exit(1) + +f_in = None +try: + f_in = open(source_file, "r", encoding="utf-8") + source = f_in.read() + f_in.close() +except FileNotFoundError: + safe_close(f_in) + print("Ошибка: файл '" + source_file + "' не найден.") + sys.exit(1) +except UnicodeDecodeError as e: + safe_close(f_in) + print("Ошибка кодировки в файле '" + source_file + "': " + str(e)) + sys.exit(1) + +try: + parse(source) + elf_file = source_file[:-4] + ".elf" + create_elf(elf_file) + + log_file = source_file[:-4] + ".log.csv" + with open(log_file, "w", encoding="utf-8") as f_log: + f_log.write("адрес;байт;целевой_адрес;исходная_команда\n") + for addr, byte, target, cmd in log_entries: + if cmd and ('"' in cmd or ';' in cmd): + cmd = '"' + cmd.replace('"', '""') + '"' + f_log.write(addr + ";" + byte + ";" + target + ";" + cmd + "\n") + print("Лог создан: " + log_file) + + print("ELF-файл создан: " + elf_file) + print("Запустить: ./" + elf_file) +except SystemExit: + raise +except Exception as e: + print("Внутренняя ошибка ассемблера: " + str(e), file=sys.stderr) + sys.exit(1) \ No newline at end of file diff --git a/short_jumps/kvs_6.py b/short_jumps/kvs_6.py new file mode 100644 index 0000000..899d250 --- /dev/null +++ b/short_jumps/kvs_6.py @@ -0,0 +1,930 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +kvs_5.py +КВС - язык программирования +без использования re +(расширенная версия с короткими переходами и полными регистрами) +""" + +import sys +import struct + +# Глобальная переменная для имени исходного файла +source_filename = "" + +def safe_close(f): + if f is not None: + f.close() + +# === Глобальные данные === +INSTRUCTIONS = { + "переместить_имм": {"code": None, "type": "reg_imm"}, + "сравнить_с": {"code": None, "type": "cmp_reg_imm"}, + "переход_если_неравно": {"code": b"\x0F\x85", "type": "jcc"}, + "вызов_системы": {"code": b"\x0F\x05", "type": "none"}, + "переход": {"code": b"\xE9", "type": "jmp"}, + # === Короткие переходы === + "короткий_переход": {"code": b"\xEB", "type": "short_jmp"}, + "короткий_переход_если_равно" : {"code": b"\x74", "type": "short_jcc"}, + "короткий_переход_если_неравно" : {"code": b"\x75", "type": "short_jcc"}, + "короткий_переход_если_меньше" : {"code": b"\x7C", "type": "short_jcc"}, + "короткий_переход_если_больше" : {"code": b"\x7F", "type": "short_jcc"}, + "короткий_переход_если_меньше_или_равно": {"code": b"\x7E", "type": "short_jcc"}, + "короткий_переход_если_больше_или_равно": {"code": b"\x7D", "type": "short_jcc"}, + "короткий_переход_если_перенос" : {"code": b"\x72", "type": "short_jcc"}, + "короткий_переход_если_нет_переноса" : {"code": b"\x73", "type": "short_jcc"}, + "короткий_переход_если_ноль" : {"code": b"\x74", "type": "short_jcc"}, + "короткий_переход_если_не_ноль" : {"code": b"\x75", "type": "short_jcc"}, + # === Новые команды для флагов === + "сравнить": {"code": b"\x48\x39", "type": "cmp_reg_reg"}, + "проверить": {"code": b"\x48\x85", "type": "test_reg_reg"}, + "вычесть": {"code": b"\x48\x29", "type": "sub_reg_reg"}, + "прибавить": {"code": b"\x48\x01", "type": "add_reg_reg"}, + "увеличить": {"code": b"\xFF", "subop": 0, "type": "incdec"}, + "уменьшить": {"code": b"\xFF", "subop": 1, "type": "incdec"}, +} + +REGISTERS = { + # 64-битные + "раикс": 0, "рсикс": 1, "рдикс": 2, "рбикс": 3, + "рсипи": 4, "рбипи": 5, "рсиай": 6, "рдиай": 7, + "р8": 8, "р9": 9, "р10": 10, "р11": 11, + "р12": 12, "р13": 13, "р14": 14, "р15": 15, + # 32-битные + "еаикс": 0, "есикс": 1, "едикс": 2, "ебикс": 3, + "есипи": 4, "ебипи": 5, "есиай": 6, "едиай": 7, + "р8д": 8, "р9д": 9, "р10д": 10, "р11д": 11, + "р12д": 12, "р13д": 13, "р14д": 14, "р15д": 15, + # 16-битные + "аикс": 0, "сикс": 1, "дикс": 2, "бикс": 3, + "эсп": 4, "бипи": 5, "эс": 6, "ди": 7, + "р8в": 8, "р9в": 9, "р10в": 10, "р11в": 11, + "р12в": 12, "р13в": 13, "р14в": 14, "р15в": 15, + # 8-битные младшие + "ал": 0, "кл": 1, "дл": 2, "бл": 3, + "спл": 4, "бпл": 5, "сил": 6, "дил": 7, + "р8б": 8, "р9б": 9, "р10б": 10, "р11б": 11, + "р12б": 12, "р13б": 13, "р14б": 14, "р15б": 15, + # 8-битные старшие (только первые 4) + "аш": 0, "чш": 1, "дш": 2, "бш": 3, +} + +# Глобальное состояние ассемблера +labels = {} +label_sections = {} +symbols = {} +sections = {".text": bytearray(), ".data": bytearray()} +current_section = ".text" +entry_point = "_start" +position = {".text": 0, ".data": 0} +pass_num = 0 + +# === Для логирования === +log_entries = [] + +# === ELF layout === +PAGE_SIZE = 0x1000 +elf_base_vaddr = 0x400000 +text_vaddr_base = 0x401000 +data_vaddr_base = 0x402000 + +text_size = 0 +data_size = 0 +comment_size = 0 +offset_text = 0 +offset_data = 0 +offset_comment = 0 +shstrtab_offset = 0 +shdr_offset = 0 +vaddr_text = 0 +vaddr_data = 0 + +def align_up(x, align): + return (x + align - 1) & ~(align - 1) + +def get_reg_info(reg_name): + if reg_name in ["аш", "чш", "дш", "бш"]: + return {"size": 8, "index": REGISTERS[reg_name], "high8": True} + elif reg_name.endswith(("б", "л")) or reg_name in ["ал", "кл", "дл", "бл", "спл", "бпл", "сил", "дил"]: + return {"size": 8, "index": REGISTERS[reg_name], "high8": False} + elif reg_name.endswith("в") or reg_name in ["аикс", "сикс", "дикс", "бикс", "эсп", "бипи", "эс", "ди"]: + return {"size": 16, "index": REGISTERS[reg_name]} + elif reg_name.endswith("д") or reg_name in ["еаикс", "есикс", "едикс", "ебикс", "есипи", "ебипи", "есиай", "едиай"]: + return {"size": 32, "index": REGISTERS[reg_name]} + else: + return {"size": 64, "index": REGISTERS[reg_name]} + +# === Функции формирования ошибок === +def make_error_msg(line_num, line_text, detail): + return "Ошибка в файле " + source_filename + ", строка " + str(line_num) + ":\n " + line_text + "\n" + detail + +def error_invalid_operand_count(mnemonic, expected, got): + return "Инструкция '" + mnemonic + "':\n ожидается " + str(expected) + " операнд(а/ов), получено: " + str(got) + +def error_unknown_mnemonic(mnemonic): + return "Неизвестная инструкция: '" + mnemonic + "'" + +def error_invalid_register(op_name, reg_name, mnemonic): + return ("Инструкция '" + mnemonic + "':\n операнд '" + op_name + "' = '" + reg_name + + "' не является допустимым регистром.\n Допустимые регистры: " + ", ".join(list(REGISTERS.keys()))) + +def error_invalid_number_format(s): + return "Недопустимый формат числа: '" + s + "'" + +def error_unknown_directive(word): + return "Неизвестная директива: '" + word + "'" + +def error_missing_label(label): + return "Метка не найдена: '" + label + "'" + +def error_unexpected_string_in_byte(): + return ".байт требует числовые значения, не строки" + +def error_unterminated_string(): + return "Незакрытая кавычка в строке" + +# === Лексер === +def tokenize_line(line): + semi = line.find(';') + if semi != -1: + line = line[:semi] + line = line.rstrip() + if not line: + return [] + tokens = [] + i = 0 + n = len(line) + while i < n: + ch = line[i] + if ch.isspace(): + i += 1 + continue + if ch == '"': + i += 1 + s = '' + while i < n and line[i] != '"': + if line[i] == '\\' and i + 1 < n: + i += 1 + esc = line[i] + if esc == 'n': + s += '\n' + elif esc == 't': + s += '\t' + elif esc == '"': + s += '"' + elif esc == '\\': + s += '\\' + else: + s += '\\' + esc + i += 1 + else: + s += line[i] + i += 1 + if i >= n: + raise ValueError(error_unterminated_string()) + i += 1 + tokens.append(('string', s)) + continue + if ch == ',': + tokens.append(('comma', ',')) + i += 1 + continue + if ch == ':': + tokens.append(('colon', ':')) + i += 1 + continue + j = i + while j < n and not (line[j].isspace() or line[j] in ',:;'): + j += 1 + word = line[i:j] + if word: + tokens.append(('word', word)) + i = j + return tokens + +# === Парсинг === +def parse_operand(operand): + if operand.isdigit(): + return int(operand) + if operand.startswith("0x"): + return int(operand, 16) + if operand in labels: + section = label_sections[operand] + if pass_num == 2: + base = vaddr_text if section == ".text" else vaddr_data + return labels[operand] + base + else: + return labels[operand] + if operand in symbols: + return symbols[operand] + raise ValueError("Неизвестный операнд: " + operand) + +def encode_instruction(mnemonic, operands, line_num, line_text): + instr = INSTRUCTIONS[mnemonic] + code = bytearray() + itype = instr["type"] + + if itype == "none": + code.extend(instr["code"]) + + elif itype == "reg_imm": + if len(operands) != 2: + raise ValueError(error_invalid_operand_count(mnemonic, 2, len(operands))) + reg_info = get_reg_info(operands[0]) + if reg_info is None: + raise ValueError(error_invalid_register("назначения", operands[0], mnemonic)) + reg = reg_info["index"] + size = reg_info["size"] + imm = parse_operand(operands[1]) + + if size == 64: + if 0 <= reg <= 7: + code.extend(b'\x48') + code.append(0xB8 + reg) + code.extend(struct.pack('= 8: + rex |= 0x01 + if rex != 0x40: + code.append(rex) + code.append(0xC7) + modrm = 0xC0 | (reg & 7) + code.append(modrm) + code.extend(struct.pack('= 8: + rex |= 0x01 + if rex != 0x40: + code.append(rex) + code.append(0xC7) + modrm = 0xC0 | (reg & 7) + code.append(modrm) + code.append(imm & 0xFF) + code.append((imm >> 8) & 0xFF) + else: + raise ValueError("16-битное значение вне диапазона") + elif size == 8: + if not (0 <= imm <= 255): + raise ValueError("8-битное значение вне диапазона 0–255") + if reg_info.get("high8"): + if reg < 4: + code.append(0xB0 + reg + 4) + code.append(imm & 0xFF) + else: + raise ValueError("Старшие байты только для первых 4 регистров") + else: + if reg < 4: + code.append(0xB0 + reg) + code.append(imm & 0xFF) + else: + rex = 0x40 + if reg >= 8: + rex |= 0x01 + code.append(rex) + code.append(0xB0 + (reg & 7)) + code.append(imm & 0xFF) + else: + raise ValueError("Неподдерживаемый размер регистра") + + elif itype == "cmp_reg_imm": + if len(operands) != 2: + raise ValueError(error_invalid_operand_count(mnemonic, 2, len(operands))) + reg_info = get_reg_info(operands[0]) + if reg_info is None: + raise ValueError(error_invalid_register("регистра", operands[0], mnemonic)) + reg = reg_info["index"] + size = reg_info["size"] + imm = parse_operand(operands[1]) + + if size == 64: + if -128 <= imm <= 127: + rex = 0x48 + if reg >= 8: + rex |= 0x01 + code.append(rex) + code.append(0x83) + modrm = 0xF8 | (reg & 7) + code.append(modrm) + code.append(imm & 0xFF) + elif -0x80000000 <= imm <= 0x7FFFFFFF: + rex = 0x48 + if reg >= 8: + rex |= 0x01 + code.append(rex) + code.append(0x81) + modrm = 0xF8 | (reg & 7) + code.append(modrm) + code.extend(struct.pack('= 8: + rex |= 0x01 + if rex != 0x40: + code.append(rex) + code.append(0x83) + modrm = 0xF8 | (reg & 7) + code.append(modrm) + code.append(imm & 0xFF) + elif -0x80000000 <= imm <= 0x7FFFFFFF: + rex = 0x40 + if reg >= 8: + rex |= 0x01 + if rex != 0x40: + code.append(rex) + code.append(0x81) + modrm = 0xF8 | (reg & 7) + code.append(modrm) + code.extend(struct.pack('= 8: + rex |= 0x01 + if rex != 0x40: + code.append(rex) + code.append(0x83) + modrm = 0xF8 | (reg & 7) + code.append(modrm) + code.append(imm & 0xFF) + elif 0 <= imm <= 0xFFFF: + code.append(0x66) + rex = 0x40 + if reg >= 8: + rex |= 0x01 + if rex != 0x40: + code.append(rex) + code.append(0x81) + modrm = 0xF8 | (reg & 7) + code.append(modrm) + code.append(imm & 0xFF) + code.append((imm >> 8) & 0xFF) + else: + raise ValueError("16-битное непосредственное значение вне диапазона") + elif size == 8: + if not (0 <= imm <= 255): + raise ValueError("8-битное значение вне диапазона 0–255") + if reg_info.get("high8"): + if reg < 4: + code.append(0x80) + modrm = 0xF8 | reg + code.append(modrm) + code.append(imm & 0xFF) + else: + raise ValueError("Старшие байты только для первых 4 регистров") + else: + if reg < 4: + code.append(0x80) + modrm = 0xF8 | reg + code.append(modrm) + code.append(imm & 0xFF) + else: + rex = 0x40 + if reg >= 8: + rex |= 0x01 + code.append(rex) + code.append(0x80) + modrm = 0xF8 | (reg & 7) + code.append(modrm) + code.append(imm & 0xFF) + else: + raise ValueError("Неподдерживаемый размер регистра") + + elif itype == "jmp": + if len(operands) != 1: + raise ValueError(error_invalid_operand_count(mnemonic, 1, len(operands))) + code.extend(instr["code"]) + target = parse_operand(operands[0]) + current_addr = vaddr_text + position[".text"] + offset = target - (current_addr + 5) + if offset < -0x80000000 or offset > 0x7FFFFFFF: + raise ValueError("Цель слишком далеко для 32-битного смещения в инструкции '" + mnemonic + "': " + str(offset)) + code.extend(struct.pack(' 0x7FFFFFFF: + raise ValueError("Цель условного перехода слишком далеко: " + str(offset)) + code.extend(struct.pack(' 127: + raise ValueError("Цель слишком далеко для короткого перехода: " + str(offset)) + code.append(0xEB) + code.append(offset & 0xFF) + + elif itype == "short_jcc": + if len(operands) != 1: + raise ValueError(error_invalid_operand_count(mnemonic, 1, len(operands))) + code.extend(instr["code"]) + target = parse_operand(operands[0]) + current_addr = vaddr_text + position[".text"] + offset = target - (current_addr + 2) + if offset < -128 or offset > 127: + raise ValueError("Цель слишком далеко для короткого условного перехода: " + str(offset)) + code.append(offset & 0xFF) + + elif itype in ("cmp_reg_reg", "test_reg_reg", "add_reg_reg", "sub_reg_reg"): + if len(operands) != 2: + raise ValueError(error_invalid_operand_count(mnemonic, 2, len(operands))) + dst_info = get_reg_info(operands[0]) + src_info = get_reg_info(operands[1]) + if dst_info is None: + raise ValueError(error_invalid_register("назначения", operands[0], mnemonic)) + if src_info is None: + raise ValueError(error_invalid_register("источника", operands[1], mnemonic)) + dst = dst_info["index"] + src = src_info["index"] + size = dst_info["size"] + if size != src_info["size"]: + raise ValueError("Размеры операндов не совпадают в инструкции '" + mnemonic + "'") + + use_66 = (size == 16) + use_rex_w = (size == 64) + rex = 0x40 + if use_rex_w: + rex |= 0x08 + if src >= 8: + rex |= 0x04 + if dst >= 8: + rex |= 0x01 + if dst_info.get("high8") or src_info.get("high8"): + if rex != 0x40: + raise ValueError("Старшие байты несовместимы с REX") + rex = 0 + + op_map = { + "cmp_reg_reg": 0x39, + "test_reg_reg": 0x85, + "add_reg_reg": 0x01, + "sub_reg_reg": 0x29, + } + op = op_map[itype] + + if use_66: + code.append(0x66) + if rex != 0x40 or use_rex_w: + code.append(rex) + code.append(op) + modrm = 0xC0 | ((src & 7) << 3) | (dst & 7) + code.append(modrm) + + elif itype == "incdec": + if len(operands) != 1: + raise ValueError(error_invalid_operand_count(mnemonic, 1, len(operands))) + reg_info = get_reg_info(operands[0]) + if reg_info is None: + raise ValueError(error_invalid_register("регистра", operands[0], mnemonic)) + reg = reg_info["index"] + size = reg_info["size"] + subop = instr["subop"] + + if size == 64: + rex = 0x48 + if reg >= 8: + rex |= 0x01 + code.append(rex) + code.append(0xFF) + elif size == 32: + rex = 0x40 + if reg >= 8: + rex |= 0x01 + if rex != 0x40: + code.append(rex) + code.append(0xFF) + elif size == 16: + code.append(0x66) + rex = 0x40 + if reg >= 8: + rex |= 0x01 + if rex != 0x40: + code.append(rex) + code.append(0xFF) + elif size == 8: + if reg_info.get("high8"): + if reg < 4: + code.append(0xFE) + else: + raise ValueError("Старшие байты только для первых 4 регистров") + else: + if reg < 4: + code.append(0xFE) + else: + rex = 0x40 + if reg >= 8: + rex |= 0x01 + code.append(rex) + code.append(0xFE) + modrm = 0xC0 | (subop << 3) | (reg & 7) + code.append(modrm) + return bytes(code) + else: + raise ValueError("Неподдерживаемый размер регистра") + + modrm = 0xC0 | (subop << 3) | (reg & 7) + code.append(modrm) + + else: + raise ValueError("Неизвестный тип инструкции: " + itype) + + return bytes(code) + + + +def parse_instruction_or_directive(tokens, line_num, line_text): + global current_section, entry_point, symbols # Не забудьте добавить symbols в global + first = tokens[0] + if first[0] != 'word': + raise ValueError("Ожидалось слово, получено: " + str(first)) + word = first[1] + if word.startswith('.'): + if word == '.текст': + current_section = ".text" + elif word == '.данные': + current_section = ".data" + elif word == '.глобал': + if len(tokens) < 2 or tokens[1][0] != 'word': + raise ValueError(".глобал требует имя метки") + entry_point = tokens[1][1] + elif word == '.строка_нуль' or word == '.строка': + if len(tokens) < 2 or tokens[1][0] != 'string': + raise ValueError(word + " требует строку в кавычках") + if current_section != ".data": + raise ValueError("Строки разрешены только в секции .data") + s = tokens[1][1] + bstring = s.encode('utf-8') + add_null = (word == '.строка_нуль') + size = len(bstring) + (1 if add_null else 0) + if pass_num == 1: + position[".data"] += size + elif pass_num == 2: + sections[".data"] += bstring + if add_null: + sections[".data"] += b'\x00' + position[".data"] += size + # === НОВАЯ ДИРЕКТИВА .КОНСТАНТА === + elif word == '.константа': + if len(tokens) < 3 or tokens[1][0] != 'word' or tokens[2][0] != 'word' or tokens[2][1] != '=' or len(tokens) < 4 or tokens[3][0] not in ('word', 'string'): # Проверяем формат: .константа имя = значение + raise ValueError(".константа требует формат: .константа <имя> = <значение>") + const_name = tokens[1][1] + const_value_str = tokens[3][1] + try: + # Попробуем распарсить значение как число или символ (если это метка) + const_value = parse_operand(const_value_str) + except ValueError: + raise ValueError("Невозможно распознать значение константы '" + const_value_str + "'") + + # Записываем в глобальный словарь символов + symbols[const_name] = const_value + # Директива .константа не добавляет байты в секцию + return + # === КОНЕЦ НОВОЙ ДИРЕКТИВЫ === + else: + raise ValueError(error_unknown_directive(word)) + return + + mnemonic = word + if mnemonic not in INSTRUCTIONS: + raise ValueError(error_unknown_mnemonic(mnemonic)) + + operands = [] + for tok in tokens[1:]: + if tok[0] == 'word': + operands.append(tok[1]) + elif tok[0] == 'comma': + continue + else: + raise ValueError("Недопустимый токен в операндах: " + str(tok)) + + if pass_num == 2: + instr_info = INSTRUCTIONS[mnemonic] + itype = instr_info["type"] + code = encode_instruction(mnemonic, operands, line_num, line_text) + start_pos = position[current_section] + + if current_section == ".text": + start_vaddr = vaddr_text + start_pos + target_addr = "" + try: + if itype in ("jmp", "jcc", "short_jmp", "short_jcc"): + target = parse_operand(operands[0]) + target_addr = hex(target) + elif itype == "reg_imm": + op_str = operands[1] + if op_str in labels: + sec = label_sections[op_str] + addr = labels[op_str] + (vaddr_text if sec == ".text" else vaddr_data) + target_addr = hex(addr) + elif op_str in symbols: # Проверяем символы + target_addr = hex(symbols[op_str]) + except Exception: + target_addr = "ошибка" + + original_cmd = line_text.split(';')[0].strip() + for i, byte in enumerate(code): + addr = start_vaddr + i + byte_hex = "{:02X}".format(byte) + cmd_to_log = original_cmd if i == 0 else "" + log_entries.append((hex(addr), byte_hex, target_addr if i == 0 else "", cmd_to_log)) + + sections[current_section] += code + position[current_section] += len(code) + else: + instr_info = INSTRUCTIONS[mnemonic] + itype = instr_info["type"] + size_map = { + "reg_imm": 10, + "cmp_reg_imm": 7, + "jmp": 5, + "jcc": 6, + "none": lambda: len(instr_info["code"]), + "short_jmp": 2, + "short_jcc": 2, + "cmp_reg_reg": 3, + "test_reg_reg": 3, + "add_reg_reg": 3, + "sub_reg_reg": 3, + "incdec": 3, + } + if itype in size_map: + sz = size_map[itype] + position[current_section] += sz() if callable(sz) else sz + else: + raise ValueError("Неподдерживаемый тип инструкции при подсчёте размера: " + itype) + + + + +def parse_tokens(tokens, line_num, line_text): + if not tokens: + return + if len(tokens) >= 2 and tokens[0][0] == 'word' and tokens[1][0] == 'colon': + label = tokens[0][1] + labels[label] = position[current_section] + label_sections[label] = current_section + rest = tokens[2:] + if rest: + parse_instruction_or_directive(rest, line_num, line_text) + return + parse_instruction_or_directive(tokens, line_num, line_text) + +def parse(source): + global pass_num, text_size, data_size, comment_size + global offset_text, offset_data, offset_comment, shstrtab_offset, shdr_offset + global vaddr_text, vaddr_data + global sections, position, log_entries + + log_entries = [] + lines = source.split('\n') + + # ПРОХОД 1 + pass_num = 1 + position[".text"] = 0 + position[".data"] = 0 + labels.clear() + label_sections.clear() + + for line_num, line in enumerate(lines, start=1): + original_line = line.rstrip() + try: + tokens = tokenize_line(line) + parse_tokens(tokens, line_num, original_line) + except Exception as e: + error_full = make_error_msg(line_num, original_line, str(e)) + print(error_full, file=sys.stderr) + sys.exit(1) + + text_size_pass1 = position[".text"] + data_size_pass1 = position[".data"] + print("ПРОХОД 1: text_size=" + str(text_size_pass1) + " bytes, data_size=" + str(data_size_pass1) + " bytes") + + # РАЗМЕЩЕНИЕ + 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_pass1, PAGE_SIZE) + vaddr_text = text_vaddr_base + vaddr_data = align_up(vaddr_text + text_size_pass1, PAGE_SIZE) + + comment_content = "Сборщик КВС".encode('utf-8') + b'\x00' + comment_size = len(comment_content) + offset_comment = align_up(offset_data + data_size_pass1, 1) + + 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_size = 64 + shdr_num = 5 + shdr_offset = align_up(shstrtab_offset + shstrtab_size, 16) + + print("РАЗМЕЩЕНИЕ: .text at offset=" + hex(offset_text) + ", .data at offset=" + hex(offset_data)) + print("ВИРТУАЛЬНЫЕ АДРЕСА: .text at " + hex(vaddr_text) + ", .data at " + hex(vaddr_data)) + print("РАССТОЯНИЕ МЕЖДУ СЕКЦИЯМИ: " + hex(vaddr_data - vaddr_text) + " bytes") + + sections[".comment"] = comment_content + + # ПРОХОД 2 + pass_num = 2 + position[".text"] = 0 + position[".data"] = 0 + sections[".text"] = bytearray() + sections[".data"] = bytearray() + + for line_num, line in enumerate(lines, start=1): + original_line = line.rstrip() + try: + tokens = tokenize_line(line) + parse_tokens(tokens, line_num, original_line) + except Exception as e: + error_full = make_error_msg(line_num, original_line, str(e)) + print(error_full, file=sys.stderr) + sys.exit(1) + + text_size_pass2 = len(sections[".text"]) + data_size_pass2 = len(sections[".data"]) + print("ПРОХОД 2: text_size=" + str(text_size_pass2) + " bytes, data_size=" + str(data_size_pass2) + " bytes") + + if text_size_pass1 != text_size_pass2: + print("ПРЕДУПРЕЖДЕНИЕ: Размер .text изменился между проходами: " + str(text_size_pass1) + " -> " + str(text_size_pass2)) + if data_size_pass1 != data_size_pass2: + print("ПРЕДУПРЕЖДЕНИЕ: Размер .data изменился между проходами: " + str(data_size_pass1) + " -> " + str(data_size_pass2)) + + text_size = text_size_pass2 + data_size = data_size_pass2 + +def create_elf(filename): + global sections, entry_point, labels, vaddr_text, vaddr_data + global offset_text, offset_data, offset_comment, shstrtab_offset, shdr_offset + + text = sections[".text"] + data = sections[".data"] + comment = sections[".comment"] + + actual_text_size = len(text) + actual_data_size = len(data) + expected_vaddr_data = align_up(vaddr_text + actual_text_size, PAGE_SIZE) + if vaddr_data != expected_vaddr_data: + print("КОРРЕКЦИЯ: vaddr_data исправлен с " + hex(vaddr_data) + " на " + hex(expected_vaddr_data)) + vaddr_data = expected_vaddr_data + + print("ФАКТИЧЕСКИЕ РАЗМЕРЫ: .text=" + str(actual_text_size) + ", .data=" + str(actual_data_size)) + print("КОНЕЧНЫЕ АДРЕСА: .text ends at " + hex(vaddr_text + actual_text_size) + ", .data starts at " + hex(vaddr_data)) + print("ПРОВЕРКА ПЕРЕКРЫТИЯ: " + ("ПЕРЕКРЫТИЕ!" if (vaddr_text + actual_text_size) > vaddr_data else "OK")) + + entry_addr = vaddr_text + labels.get(entry_point, 0) + + shstrtab_content = b"\x00.text\x00.data\x00.comment\x00.shstrtab\x00" + shstrtab_size = len(shstrtab_content) + + elf_header_size = 64 + ph_size = 56 + ph_num = 3 + shdr_size = 64 + shdr_num = 5 + + 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('") + sys.exit(1) + +source_file = sys.argv[1] +source_filename = source_file +if not source_file.endswith('.квс'): + print("Ошибка: файл должен иметь расширение .квс") + sys.exit(1) + +f_in = None +try: + f_in = open(source_file, "r", encoding="utf-8") + source = f_in.read() + f_in.close() +except FileNotFoundError: + safe_close(f_in) + print("Ошибка: файл '" + source_file + "' не найден.") + sys.exit(1) +except UnicodeDecodeError as e: + safe_close(f_in) + print("Ошибка кодировки в файле '" + source_file + "': " + str(e)) + sys.exit(1) + +try: + parse(source) + elf_file = source_file[:-4] + ".elf" + create_elf(elf_file) + + log_file = source_file[:-4] + ".log.csv" + f_log = open(log_file, "w", encoding="utf-8") + f_log.write("адрес;байт;целевой_адрес;исходная_команда\n") + for addr, byte, target, cmd in log_entries: + if cmd and ('"' in cmd or ';' in cmd): + cmd = '"' + cmd.replace('"', '""') + '"' + f_log.write(addr + ";" + byte + ";" + target + ";" + cmd + "\n") + f_log.close() + print("Лог создан: " + log_file) + + print("ELF-файл создан: " + elf_file) + print("Запустить: ./" + elf_file) +except SystemExit: + raise +except Exception as e: + print("Внутренняя ошибка ассемблера: " + str(e), file=sys.stderr) + sys.exit(1) \ No newline at end of file diff --git a/short_jumps/дебаг.квс b/short_jumps/дебаг.квс new file mode 100644 index 0000000..7a832ce --- /dev/null +++ b/short_jumps/дебаг.квс @@ -0,0 +1,33 @@ +.текст +.глобал _start + +_start: + ; Устанавливаем rax в 1 (не ноль) + переместить_имм раикс, 1 + ; jnz должен сработать, прыгая к print + короткий_переход_если_не_ноль print_msg + + ; Мертвый код - НЕ должен выполниться + переместить_имм раикс, 1 ; write syscall + переместить_имм рдиай, 1 ; stdout + переместить_имм рсиай, dead_msg + переместить_имм рдикс, len_dead_msg + вызов_системы + +print_msg: + переместить_имм раикс, 1 ; write syscall + переместить_имм рдиай, 1 ; stdout + переместить_имм рсиай, alive_msg + переместить_имм рдикс, len_alive_msg + вызов_системы + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные +dead_msg: .строка_нуль "Это НЕ должно напечататься." +.константа len_dead_msg = 28 +alive_msg: .строка_нуль "Это ДОЛЖНО напечататься." +.константа len_alive_msg = 46 \ No newline at end of file diff --git a/short_jumps/привеет.квс b/short_jumps/привеет.квс new file mode 100644 index 0000000..ba67231 --- /dev/null +++ b/short_jumps/привеет.квс @@ -0,0 +1,35 @@ +.текст +.глобал _start + +_start: + ; Инициализация: raikc = 0 → пропустить первую строку + ; Попробуйте изменить на 1 — тогда обе строки напечатаются + переместить_имм раикс, 1 + сравнить_с раикс, 0 ; ← обязательно! + + ; Если raikc == 0 → прыгаем к выводу второй строки + короткий_переход_если_ноль пропустить_первую + + ; Вывод первой строки + переместить_имм раикс, 1 ; write + переместить_имм рдиай, 1 ; stdout + переместить_имм рсиай, msg0 ; адрес строки + переместить_имм рдикс, 21 ; длина "Привет мир!\n" = 13 байт + вызов_системы + +пропустить_первую: + ; Всегда выводим вторую строку + переместить_имм раикс, 1 ; write + переместить_имм рдиай, 1 ; stdout + переместить_имм рсиай, msg1 ; адрес строки + переместить_имм рдикс, 21 ; длина "Поди прочь!\n" = 13 байт + вызов_системы + + ; Завершение + переместить_имм раикс, 60 ; exit + переместить_имм рдиай, 0 ; код возврата + вызов_системы + +.данные +msg0: .строка_нуль "Привет мир!\n" +msg1: .строка_нуль "Поди прочь!\n" \ No newline at end of file diff --git a/short_jumps/сложный_тест0.квс b/short_jumps/сложный_тест0.квс new file mode 100644 index 0000000..f7eff25 --- /dev/null +++ b/short_jumps/сложный_тест0.квс @@ -0,0 +1,53 @@ +; сложный тест0.квс +; Тест: один переход и один мусорный сегмент + +.текст +.глобал _start + +_start: + ; Инициализация регистра + переместить_имм раикс, 10 ; rax = 10 (не ноль) + + ; ПЕРВЫЙ ПЕРЕХОД: короткий_переход_если_не_ноль + ; ZF=0 (так как rax=10), значит jnz сработает + ; Прыгаем к метке 'вывести_сообщение', пропуская мертвый_код_1 + короткий_переход_если_не_ноль вывести_сообщение + + ; --- МЕРТВЫЙ КОД 1 --- + ; Этот код НЕ должен выполниться + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_1 + переместить_имм рдикс, len_msg_dead_1 + вызов_системы + ; --------------------- + + ; --- КОД ОШИБКИ (на всякий случай) --- + ; Если мы сюда попали, значит переход НЕ сработал (ошибка) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_fail + переместить_имм рдикс, len_msg_fail + вызов_системы + + ; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ --- +вывести_сообщение: + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_success + переместить_имм рдикс, len_msg_success + вызов_системы + + ; --- ЗАВЕРШЕНИЕ --- + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные + ; Перемешиваем строки и константы + msg_success: .строка_нуль "Успех!\n" + .константа len_msg_success = 13 + msg_dead_1: .строка_нуль "Мертвый код 1!" + .константа len_msg_dead_1 = 14 + msg_fail: .строка_нуль "Ошибка: переход не сработал!" + .константа len_msg_fail = 28 diff --git a/short_jumps/сложный_тест1.квс b/short_jumps/сложный_тест1.квс new file mode 100644 index 0000000..bf7d566 --- /dev/null +++ b/short_jumps/сложный_тест1.квс @@ -0,0 +1,131 @@ +; сложный_тест1.квс +; Тест: два перехода и два мусорных сегмента + +.текст +.глобал _start + +_start: + ; Инициализация регистров + переместить_имм раикс, 10 ; rax = 10 (не ноль) + переместить_имм рбикс, 5 ; rbx = 5 (для сравнения) + + ; ПЕРВЫЙ ПЕРЕХОД: короткий_переход_если_не_ноль + ; ZF=0 (так как rax=10), значит jnz сработает + ; Прыгаем к метке 'проверка_2', пропуская мертвый_код_1 + короткий_переход_если_не_ноль проверка_2 + + ; --- МЕРТВЫЙ КОД 1 --- + ; Этот код НЕ должен выполниться + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_1 + переместить_имм рдикс, len_msg_dead_1 + вызов_системы + ; --------------------- + +проверка_2: + ; ВТОРОЙ ПЕРЕХОД: короткий_переход_если_равно + ; Сравниваем rax (10) и rbx (5) -> ZF=0 + сравнить раикс, рбикс + ; ZF=0, значит je НЕ сработает. + ; Нам нужно ПРЫГНУТЬ через мертвый код, если ZF НЕ 1 (т.е. ZF = 0). + ; У нас нет инструкции 'короткий_переход_если_не_равно' (jne), но она эквивалентна 'короткий_переход_если_не_ноль' (jnz) для флага ZF. + ; Однако, у нас есть 'короткий_переход_если_равно' (je), который сработает при ZF=1. + ; Мы хотим, чтобы переход НЕ срабатывал при ZF=0. + ; Поэтому мы используем 'короткий_переход_если_равно' и прыгаем к метке ПОСЛЕ мертвого кода, если ZF=1. + ; Но ZF=0, поэтому переход НЕ сработает, и выполнение пойдёт на следующую инструкцию - в мертвый код. + ; Нам нужно наоборот: прыгнуть, если ZF=0. + ; Используем безусловный переход ПОСЛЕ мертвого кода, чтобы обойти его, если ZF=0. + ; Правильная логика: + ; cmp ... + ; je мимо_мертвого_кода_2 (переход, если ZF=1) + ; [мертвый код 2] + ; мимо_мертвого_кода_2: + ; [продолжение кода] + + ; Итак, мы хотим прыгнуть МИМО мертвого кода 2, если ZF=0 (т.е. если НЕ равны). + ; У нас есть только 'je'. Значит, мы прыгаем МИМО, если ZF=1 (равны). + ; Мы НЕ хотим прыгать мимо, если ZF=0. + ; Поэтому: cmp, je (прыгнуть мимо, если ZF=1), [мертвый код], [метка мимо], [остальной код] + ; Это означает: если ZF=1 -> прыгаем мимо. Если ZF=0 -> выполняем мертвый код. + ; Это НЕ то, что нам нужно. + + ; Нам нужно: если ZF=0 -> прыгаем мимо. Если ZF=1 -> выполняем мертвый код (или идём дальше в него). + ; У нас нет jne/jnz. Используем логику: если НЕ (ZF=1), то прыгаем. + ; Или: используем безусловный переход после мертвого кода, но перед ним поставим je на метку ПОСЛЕ безусловного перехода. + ; Это хитро, но работает: + ; cmp rax, rbx + ; je метка_после_безусловного (ZF=1 -> прыгаем, обходим безусловный переход) + ; короткий_переход мимо_мертвого_кода_2 (ZF=0 -> прыгаем через мертвый код) + ; метка_после_безусловного: + ; [мертвый код 2 - выполнится, если ZF=1] + ; мимо_мертвого_кода_2: + ; [продолжение] + + ; Но мы хотим, чтобы мертвый код НЕ выполнялся, если ZF=0. + ; cmp rax, rbx (ZF = 0) + ; je метка_после_безусловного (ZF=0, переход НЕ сработает) + ; короткий_переход мимо_мертвого_кода_2 (ZF=0, переход СРАБОТАЕТ, прыгаем мимо) + ; метка_после_безусловного: [попадаем сюда, если ZF=1] + ; [мертвый код 2 - выполнится, если ZF=1] + ; мимо_мертвого_кода_2: [попадаем сюда, если ZF=0 (прыгнули) или если ZF=1 (прошли через мертвый код)] + ; [продолжение кода] + + ; Это работает! Если ZF=0 (не равны), мы прыгаем мимо мертвого кода 2. + ; Если ZF=1 (равны), мы пропускаем безусловный переход и попадаем в мертвый код 2. + ; Нам нужно наоборот: прыгать мимо, если ZF=0 (не равны). + ; Значит, если cmp показывает НЕ равны (ZF=0), мы хотим прыгнуть. + ; У нас нет jne. Но мы можем использовать логику: if (ZF == 0) jmp; (псевдокод). + ; Это можно выразить как: if (ZF == 1) goto skip_jmp; jmp target; skip_jmp: ... (псевдокод). + ; Это и есть: cmp ...; je skip_jmp; jmp target; skip_jmp: ... + ; Где 'jmp target' - это прыжок, который происходит, если ZF=0 (т.е. когда je НЕ сработал). + ; Итак: + ; cmp rax, rbx (ZF=0) + ; je skip_jmp (ZF=0, переход НЕ сработает -> идем дальше) + ; короткий_переход мимо_мертвого_кода_2 (ZF=0, СРАБОТАЕТ -> прыгаем мимо мертвого кода) + ; skip_jmp: (ZF=1, мы сюда попали, прыгнув через безусловный переход) + ; [мертвый код 2 - выполнится ТОЛЬКО если ZF=1] + ; мимо_мертвого_кода_2: + ; [продолжение] + + ; Это как раз то, что нужно! + ; cmp rax, rbx (ZF=0) + ; je skip_jmp (ZF=0 -> не прыгаем) + ; короткий_переход мимо_мертвого_кода_2 (ZF=0 -> прыгаем мимо мертвого кода 2) + ; skip_jmp: (ZF=1 -> сюда попали, прыгнув через безусловный переход) + сравнить раикс, рбикс + короткий_переход_если_равно skip_jmp + короткий_переход мимо_мертвого_кода_2 +skip_jmp: + ; --- МЕРТВЫЙ КОД 2 --- + ; Этот код НЕ должен выполниться (так как ZF=0) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_2 + переместить_имм рдикс, len_msg_dead_2 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_2: + + ; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ --- +вывести_сообщение: + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_success + переместить_имм рдикс, len_msg_success + вызов_системы + + ; --- ЗАВЕРШЕНИЕ --- + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные + ; Перемешиваем строки и константы + msg_success: .строка_нуль "Успех!\n" + .константа len_msg_success = 13 ; Исправлено на длину "Успех!\n" (10 байт + 1 \n) + msg_dead_2: .строка_нуль "Мертвый код 2!" + .константа len_msg_dead_2 = 14 + msg_dead_1: .строка_нуль "Мертвый код 1!" + .константа len_msg_dead_1 = 14 diff --git a/short_jumps/сложный_тест2.квс b/short_jumps/сложный_тест2.квс new file mode 100644 index 0000000..6aee528 --- /dev/null +++ b/short_jumps/сложный_тест2.квс @@ -0,0 +1,93 @@ +; сложный_тест2.квс +; Тест: три перехода и три мусорных сегмента + +.текст +.глобал _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: + ; ВТОРОЙ ПЕРЕХОД: короткий_переход_если_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> ZF=0 + сравнить раикс, рбикс + ; ZF=0, значит je НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 2, если ZF=0. + ; Используем: je skip_jmp_2 (переход НЕ сработает); jmp мимо_мертвого_кода_2 (переход СРАБОТАЕТ) + короткий_переход_если_равно skip_jmp_2 + короткий_переход мимо_мертвого_кода_2 +skip_jmp_2: + ; --- МЕРТВЫЙ КОД 2 --- + ; Этот код НЕ должен выполниться (так как ZF=0) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_2 + переместить_имм рдикс, len_msg_dead_2 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_2: + + ; ТРЕТИЙ ПЕРЕХОД: короткий_переход_если_меньше (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, SF=0, OF=0 + сравнить раикс, рбикс + ; SF=0, OF=0. Условие jl: SF != OF (0 != 0 - ложь). jl НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 3, если jl НЕ сработает (т.е. если rax >= rbx). + ; Используем: jl skip_jmp_3 (переход НЕ сработает); jmp мимо_мертвого_кода_3 (переход СРАБОТАЕТ) + короткий_переход_если_меньше skip_jmp_3 + короткий_переход мимо_мертвого_кода_3 +skip_jmp_3: + ; --- МЕРТВЫЙ КОД 3 --- + ; Этот код НЕ должен выполниться (так как jl не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_3 + переместить_имм рдикс, len_msg_dead_3 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_3: + + ; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ --- +вывести_сообщение: + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_success + переместить_имм рдикс, len_msg_success + вызов_системы + + ; --- ЗАВЕРШЕНИЕ --- + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные + ; Перемешиваем строки и константы + msg_success: .строка_нуль "Успех!\n" + .константа len_msg_success = 13 + ; "Мертвый код 3!" = 12 букв * 3 байта + 1 (!) = 36 + 1 = 37 байт. len = 37 + msg_dead_3: .строка_нуль "Мертвый код 3!" + .константа len_msg_dead_3 = 37 + ; "Мертвый код 2!" = 12 букв * 3 байта + 1 (!) = 36 + 1 = 37 байт. len = 37 + msg_dead_2: .строка_нуль "Мертвый код 2!" + .константа len_msg_dead_2 = 37 + ; "Мертвый код 1!" = 12 букв * 3 байта + 1 (!) = 36 + 1 = 37 байт. len = 37 + msg_dead_1: .строка_нуль "Мертвый код 1!" + .константа len_msg_dead_1 = 37 diff --git a/short_jumps/сложный_тест3.квс b/short_jumps/сложный_тест3.квс new file mode 100644 index 0000000..8f0cae9 --- /dev/null +++ b/short_jumps/сложный_тест3.квс @@ -0,0 +1,114 @@ +; сложный_тест3.квс +; Тест: четыре перехода и четыре мусорных сегмента + +.текст +.глобал _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: + ; ВТОРОЙ ПЕРЕХОД: короткий_переход_если_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> ZF=0 + сравнить раикс, рбикс + ; ZF=0, значит je НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 2, если ZF=0. + ; Используем: je skip_jmp_2 (переход НЕ сработает); jmp мимо_мертвого_кода_2 (переход СРАБОТАЕТ) + короткий_переход_если_равно skip_jmp_2 + короткий_переход мимо_мертвого_кода_2 +skip_jmp_2: + ; --- МЕРТВЫЙ КОД 2 --- + ; Этот код НЕ должен выполниться (так как ZF=0) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_2 + переместить_имм рдикс, len_msg_dead_2 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_2: + + ; ТРЕТИЙ ПЕРЕХОД: короткий_переход_если_меньше (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, SF=0, OF=0 + сравнить раикс, рбикс + ; SF=0, OF=0. Условие jl: SF != OF (0 != 0 - ложь). jl НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 3, если jl НЕ сработает (т.е. если rax >= rbx). + ; Используем: jl skip_jmp_3 (переход НЕ сработает); jmp мимо_мертвого_кода_3 (переход СРАБОТАЕТ) + короткий_переход_если_меньше skip_jmp_3 + короткий_переход мимо_мертвого_кода_3 +skip_jmp_3: + ; --- МЕРТВЫЙ КОД 3 --- + ; Этот код НЕ должен выполниться (так как jl не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_3 + переместить_имм рдикс, len_msg_dead_3 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_3: + + ; ЧЕТВЁРТЫЙ ПЕРЕХОД: короткий_переход_если_больше + ; Сравниваем 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: + + ; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ --- +вывести_сообщение: + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_success + переместить_имм рдикс, len_msg_success + вызов_системы + + ; --- ЗАВЕРШЕНИЕ --- + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные + ; Перемешиваем строки и константы + ; "Успех!\n" = 5 букв * 2 + 1 (!) + 2 (\n) = 13 байт на содержимое. len = 13 + msg_success: .строка_нуль "Успех!\n" + .константа len_msg_success = 13 + ; "Мертвый код 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 diff --git a/short_jumps/сложный_тест4.квс b/short_jumps/сложный_тест4.квс new file mode 100644 index 0000000..d112db3 --- /dev/null +++ b/short_jumps/сложный_тест4.квс @@ -0,0 +1,137 @@ +; сложный_тест4.квс +; Тест: пять переходов и пять мусорных сегментов + +.текст +.глобал _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: + ; ВТОРОЙ ПЕРЕХОД: короткий_переход_если_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> ZF=0 + сравнить раикс, рбикс + ; ZF=0, значит je НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 2, если ZF=0. + ; Используем: je skip_jmp_2 (переход НЕ сработает); jmp мимо_мертвого_кода_2 (переход СРАБОТАЕТ) + короткий_переход_если_равно skip_jmp_2 + короткий_переход мимо_мертвого_кода_2 +skip_jmp_2: + ; --- МЕРТВЫЙ КОД 2 --- + ; Этот код НЕ должен выполниться (так как ZF=0) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_2 + переместить_имм рдикс, len_msg_dead_2 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_2: + + ; ТРЕТИЙ ПЕРЕХОД: короткий_переход_если_меньше (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, SF=0, OF=0 + сравнить раикс, рбикс + ; SF=0, OF=0. Условие jl: SF != OF (0 != 0 - ложь). jl НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 3, если jl НЕ сработает (т.е. если rax >= rbx). + ; Используем: jl skip_jmp_3 (переход НЕ сработает); jmp мимо_мертвого_кода_3 (переход СРАБОТАЕТ) + короткий_переход_если_меньше skip_jmp_3 + короткий_переход мимо_мертвого_кода_3 +skip_jmp_3: + ; --- МЕРТВЫЙ КОД 3 --- + ; Этот код НЕ должен выполниться (так как jl не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_3 + переместить_имм рдикс, len_msg_dead_3 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_3: + + ; ЧЕТВЁРТЫЙ ПЕРЕХОД: короткий_переход_если_больше + ; Сравниваем 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: + + ; ПЯТЫЙ ПЕРЕХОД: короткий_переход_если_меньше_или_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0 + сравнить раикс, рбикс + ; Условие jle: ZF=1 ИЛИ SF != OF. ZF=0 (ложь), SF != OF (0 != 0, ложь). jle НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 5, если jle НЕ сработает (т.е. если rax > rbx). + ; Используем: jle skip_jmp_5 (переход НЕ сработает); jmp мимо_мертвого_кода_5 (переход СРАБОТАЕТ) + короткий_переход_если_меньше_или_равно skip_jmp_5 + короткий_переход мимо_мертвого_кода_5 +skip_jmp_5: + ; --- МЕРТВЫЙ КОД 5 --- + ; Этот код НЕ должен выполниться (так как jle не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_5 + переместить_имм рдикс, len_msg_dead_5 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_5: + + ; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ --- +вывести_сообщение: + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_success + переместить_имм рдикс, len_msg_success + вызов_системы + + ; --- ЗАВЕРШЕНИЕ --- + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные + ; Перемешиваем строки и константы + ; "Успех!\n" = 5 букв * 2 + 1 (!) + 2 (\n) = 13 байт на содержимое. len = 13 + msg_success: .строка_нуль "Успех!\n" + .константа len_msg_success = 13 + ; "Мертвый код 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 diff --git a/short_jumps/сложный_тест5.квс b/short_jumps/сложный_тест5.квс new file mode 100644 index 0000000..33b7c75 --- /dev/null +++ b/short_jumps/сложный_тест5.квс @@ -0,0 +1,157 @@ +; сложный_тест5.квс +; Тест: шесть переходов и шесть мусорных сегментов + +.текст +.глобал _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: + ; ВТОРОЙ ПЕРЕХОД: короткий_переход_если_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> ZF=0 + сравнить раикс, рбикс + ; ZF=0, значит je НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 2, если ZF=0. + ; Используем: je skip_jmp_2 (переход НЕ сработает); jmp мимо_мертвого_кода_2 (переход СРАБОТАЕТ) + короткий_переход_если_равно skip_jmp_2 + короткий_переход мимо_мертвого_кода_2 +skip_jmp_2: + ; --- МЕРТВЫЙ КОД 2 --- + ; Этот код НЕ должен выполниться (так как ZF=0) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_2 + переместить_имм рдикс, len_msg_dead_2 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_2: + + ; ТРЕТИЙ ПЕРЕХОД: короткий_переход_если_меньше (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, SF=0, OF=0 + сравнить раикс, рбикс + ; SF=0, OF=0. Условие jl: SF != OF (0 != 0 - ложь). jl НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 3, если jl НЕ сработает (т.е. если rax >= rbx). + ; Используем: jl skip_jmp_3 (переход НЕ сработает); jmp мимо_мертвого_кода_3 (переход СРАБОТАЕТ) + короткий_переход_если_меньше skip_jmp_3 + короткий_переход мимо_мертвого_кода_3 +skip_jmp_3: + ; --- МЕРТВЫЙ КОД 3 --- + ; Этот код НЕ должен выполниться (так как jl не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_3 + переместить_имм рдикс, len_msg_dead_3 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_3: + + ; ЧЕТВЁРТЫЙ ПЕРЕХОД: короткий_переход_если_больше + ; Сравниваем 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: + + ; ПЯТЫЙ ПЕРЕХОД: короткий_переход_если_меньше_или_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0 + сравнить раикс, рбикс + ; Условие jle: ZF=1 ИЛИ SF != OF. ZF=0 (ложь), SF != OF (0 != 0, ложь). jle НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 5, если jle НЕ сработает (т.е. если rax > rbx). + ; Используем: jle skip_jmp_5 (переход НЕ сработает); jmp мимо_мертвого_кода_5 (переход СРАБОТАЕТ) + короткий_переход_если_меньше_или_равно skip_jmp_5 + короткий_переход мимо_мертвого_кода_5 +skip_jmp_5: + ; --- МЕРТВЫЙ КОД 5 --- + ; Этот код НЕ должен выполниться (так как jle не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_5 + переместить_имм рдикс, len_msg_dead_5 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_5: + + ; ШЕСТОЙ ПЕРЕХОД: короткий_переход_если_больше_или_равно + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0 + сравнить раикс, рбикс + ; Условие jge: SF=OF. SF=0, OF=0, SF=OF (0=0). jge СРАБОТАЕТ. + ; Мы хотим прыгнуть МИМО мертвого кода 6, если jge сработает (т.е. если rax >= rbx). + короткий_переход_если_больше_или_равно мимо_мертвого_кода_6 + ; --- МЕРТВЫЙ КОД 6 --- + ; Этот код НЕ должен выполниться (так как jge сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_6 + переместить_имм рдикс, len_msg_dead_6 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_6: + + ; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ --- +вывести_сообщение: + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_success + переместить_имм рдикс, len_msg_success + вызов_системы + + ; --- ЗАВЕРШЕНИЕ --- + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные + ; Перемешиваем строки и константы + ; "Успех!\n" = 5 букв * 2 + 1 (!) + 2 (\n) = 13 байт на содержимое. len = 13 + msg_success: .строка_нуль "Успех!\n" + .константа len_msg_success = 13 + ; "Мертвый код 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 diff --git a/short_jumps/сложный_тест6.квс b/short_jumps/сложный_тест6.квс new file mode 100644 index 0000000..439c9ad --- /dev/null +++ b/short_jumps/сложный_тест6.квс @@ -0,0 +1,180 @@ +; сложный_тест6.квс +; Тест: семь переходов и семь мусорных сегментов + +.текст +.глобал _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: + ; ВТОРОЙ ПЕРЕХОД: короткий_переход_если_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> ZF=0 + сравнить раикс, рбикс + ; ZF=0, значит je НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 2, если ZF=0. + ; Используем: je skip_jmp_2 (переход НЕ сработает); jmp мимо_мертвого_кода_2 (переход СРАБОТАЕТ) + короткий_переход_если_равно skip_jmp_2 + короткий_переход мимо_мертвого_кода_2 +skip_jmp_2: + ; --- МЕРТВЫЙ КОД 2 --- + ; Этот код НЕ должен выполниться (так как ZF=0) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_2 + переместить_имм рдикс, len_msg_dead_2 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_2: + + ; ТРЕТИЙ ПЕРЕХОД: короткий_переход_если_меньше (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, SF=0, OF=0 + сравнить раикс, рбикс + ; SF=0, OF=0. Условие jl: SF != OF (0 != 0 - ложь). jl НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 3, если jl НЕ сработает (т.е. если rax >= rbx). + ; Используем: jl skip_jmp_3 (переход НЕ сработает); jmp мимо_мертвого_кода_3 (переход СРАБОТАЕТ) + короткий_переход_если_меньше skip_jmp_3 + короткий_переход мимо_мертвого_кода_3 +skip_jmp_3: + ; --- МЕРТВЫЙ КОД 3 --- + ; Этот код НЕ должен выполниться (так как jl не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_3 + переместить_имм рдикс, len_msg_dead_3 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_3: + + ; ЧЕТВЁРТЫЙ ПЕРЕХОД: короткий_переход_если_больше + ; Сравниваем 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: + + ; ПЯТЫЙ ПЕРЕХОД: короткий_переход_если_меньше_или_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0 + сравнить раикс, рбикс + ; Условие jle: ZF=1 ИЛИ SF != OF. ZF=0 (ложь), SF != OF (0 != 0, ложь). jle НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 5, если jle НЕ сработает (т.е. если rax > rbx). + ; Используем: jle skip_jmp_5 (переход НЕ сработает); jmp мимо_мертвого_кода_5 (переход СРАБОТАЕТ) + короткий_переход_если_меньше_или_равно skip_jmp_5 + короткий_переход мимо_мертвого_кода_5 +skip_jmp_5: + ; --- МЕРТВЫЙ КОД 5 --- + ; Этот код НЕ должен выполниться (так как jle не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_5 + переместить_имм рдикс, len_msg_dead_5 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_5: + + ; ШЕСТОЙ ПЕРЕХОД: короткий_переход_если_больше_или_равно + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0 + сравнить раикс, рбикс + ; Условие jge: SF=OF. SF=0, OF=0, SF=OF (0=0). jge СРАБОТАЕТ. + ; Мы хотим прыгнуть МИМО мертвого кода 6, если jge сработает (т.е. если rax >= rbx). + короткий_переход_если_больше_или_равно мимо_мертвого_кода_6 + ; --- МЕРТВЫЙ КОД 6 --- + ; Этот код НЕ должен выполниться (так как jge сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_6 + переместить_имм рдикс, len_msg_dead_6 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_6: + + ; СЕДЬМОЙ ПЕРЕХОД: короткий_переход_если_перенос + ; Выполним вычитание, которое вызовет перенос: 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 СРАБОТАЕТ. + ; Мы хотим прыгнуть МИМО мертвого кода 7, если jc сработает (т.е. если был перенос). + короткий_переход_если_перенос мимо_мертвого_кода_7 + ; --- МЕРТВЫЙ КОД 7 --- + ; Этот код НЕ должен выполниться (так как jc сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_7 + переместить_имм рдикс, len_msg_dead_7 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_7: + + ; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ --- +вывести_сообщение: + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_success + переместить_имм рдикс, len_msg_success + вызов_системы + + ; --- ЗАВЕРШЕНИЕ --- + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные + ; Перемешиваем строки и константы + ; "Успех!\n" = 5 букв * 2 + 1 (!) + 2 (\n) = 13 байт на содержимое. len = 13 + msg_success: .строка_нуль "Успех!\n" + .константа len_msg_success = 13 + ; "Мертвый код 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 diff --git a/short_jumps/сложный_тест7.квс b/short_jumps/сложный_тест7.квс new file mode 100644 index 0000000..5983222 --- /dev/null +++ b/short_jumps/сложный_тест7.квс @@ -0,0 +1,200 @@ +; сложный_тест7.квс +; Тест: восемь переходов и восемь мусорных сегментов + +.текст +.глобал _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: + ; ВТОРОЙ ПЕРЕХОД: короткий_переход_если_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> ZF=0 + сравнить раикс, рбикс + ; ZF=0, значит je НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 2, если ZF=0. + ; Используем: je skip_jmp_2 (переход НЕ сработает); jmp мимо_мертвого_кода_2 (переход СРАБОТАЕТ) + короткий_переход_если_равно skip_jmp_2 + короткий_переход мимо_мертвого_кода_2 +skip_jmp_2: + ; --- МЕРТВЫЙ КОД 2 --- + ; Этот код НЕ должен выполниться (так как ZF=0) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_2 + переместить_имм рдикс, len_msg_dead_2 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_2: + + ; ТРЕТИЙ ПЕРЕХОД: короткий_переход_если_меньше (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, SF=0, OF=0 + сравнить раикс, рбикс + ; SF=0, OF=0. Условие jl: SF != OF (0 != 0 - ложь). jl НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 3, если jl НЕ сработает (т.е. если rax >= rbx). + ; Используем: jl skip_jmp_3 (переход НЕ сработает); jmp мимо_мертвого_кода_3 (переход СРАБОТАЕТ) + короткий_переход_если_меньше skip_jmp_3 + короткий_переход мимо_мертвого_кода_3 +skip_jmp_3: + ; --- МЕРТВЫЙ КОД 3 --- + ; Этот код НЕ должен выполниться (так как jl не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_3 + переместить_имм рдикс, len_msg_dead_3 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_3: + + ; ЧЕТВЁРТЫЙ ПЕРЕХОД: короткий_переход_если_больше + ; Сравниваем 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: + + ; ПЯТЫЙ ПЕРЕХОД: короткий_переход_если_меньше_или_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0 + сравнить раикс, рбикс + ; Условие jle: ZF=1 ИЛИ SF != OF. ZF=0 (ложь), SF != OF (0 != 0, ложь). jle НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 5, если jle НЕ сработает (т.е. если rax > rbx). + ; Используем: jle skip_jmp_5 (переход НЕ сработает); jmp мимо_мертвого_кода_5 (переход СРАБОТАЕТ) + короткий_переход_если_меньше_или_равно skip_jmp_5 + короткий_переход мимо_мертвого_кода_5 +skip_jmp_5: + ; --- МЕРТВЫЙ КОД 5 --- + ; Этот код НЕ должен выполниться (так как jle не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_5 + переместить_имм рдикс, len_msg_dead_5 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_5: + + ; ШЕСТОЙ ПЕРЕХОД: короткий_переход_если_больше_или_равно + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0 + сравнить раикс, рбикс + ; Условие jge: SF=OF. SF=0, OF=0, SF=OF (0=0). jge СРАБОТАЕТ. + ; Мы хотим прыгнуть МИМО мертвого кода 6, если jge сработает (т.е. если rax >= rbx). + короткий_переход_если_больше_или_равно мимо_мертвого_кода_6 + ; --- МЕРТВЫЙ КОД 6 --- + ; Этот код НЕ должен выполниться (так как jge сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_6 + переместить_имм рдикс, len_msg_dead_6 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_6: + + ; СЕДЬМОЙ ПЕРЕХОД: короткий_переход_если_перенос + ; Выполним вычитание, которое вызовет перенос: 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 СРАБОТАЕТ. + ; Мы хотим прыгнуть МИМО мертвого кода 7, если jc сработает (т.е. если был перенос). + короткий_переход_если_перенос мимо_мертвого_кода_7 + ; --- МЕРТВЫЙ КОД 7 --- + ; Этот код НЕ должен выполниться (так как jc сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_7 + переместить_имм рдикс, len_msg_dead_7 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_7: + + ; ВОСЬМОЙ ПЕРЕХОД: короткий_переход_если_нет_переноса + ; Убедимся, что CF=0. Выполним операцию, которая сбросит CF. + сравнить раикс, раикс ; CF = 0 (так как rax - rax = 0, без переноса) + ; Условие jnc: CF=0. CF=0. jnc СРАБОТАЕТ. + ; Мы хотим прыгнуть МИМО мертвого кода 8, если jnc сработает (т.е. если НЕ было переноса). + короткий_переход_если_нет_переноса мимо_мертвого_кода_8 + ; --- МЕРТВЫЙ КОД 8 --- + ; Этот код НЕ должен выполниться (так как jnc сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_8 + переместить_имм рдикс, len_msg_dead_8 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_8: + + ; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ --- +вывести_сообщение: + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_success + переместить_имм рдикс, len_msg_success + вызов_системы + + ; --- ЗАВЕРШЕНИЕ --- + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные + ; Перемешиваем строки и константы + ; "Успех!\n" = 5 букв * 2 + 1 (!) + 2 (\n) = 13 байт на содержимое. len = 13 + msg_success: .строка_нуль "Успех!\n" + .константа len_msg_success = 13 + ; "Мертвый код 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 diff --git a/short_jumps/сложный_тест8.квс b/short_jumps/сложный_тест8.квс new file mode 100644 index 0000000..1ca4d15 --- /dev/null +++ b/short_jumps/сложный_тест8.квс @@ -0,0 +1,217 @@ +; сложный_тест8.квс +; Тест: девять переходов и девять мусорных сегментов (включая короткий безусловный) + +.текст +.глобал _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: + ; ВТОРОЙ ПЕРЕХОД: короткий_переход_если_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> ZF=0 + сравнить раикс, рбикс + ; ZF=0, значит je НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 2, если ZF=0. + ; Используем: je skip_jmp_2 (переход НЕ сработает); jmp мимо_мертвого_кода_2 (переход СРАБОТАЕТ) + короткий_переход_если_равно skip_jmp_2 + короткий_переход мимо_мертвого_кода_2 +skip_jmp_2: + ; --- МЕРТВЫЙ КОД 2 --- + ; Этот код НЕ должен выполниться (так как ZF=0) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_2 + переместить_имм рдикс, len_msg_dead_2 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_2: + + ; ТРЕТИЙ ПЕРЕХОД: короткий_переход_если_меньше (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, SF=0, OF=0 + сравнить раикс, рбикс + ; SF=0, OF=0. Условие jl: SF != OF (0 != 0 - ложь). jl НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 3, если jl НЕ сработает (т.е. если rax >= rbx). + ; Используем: jl skip_jmp_3 (переход НЕ сработает); jmp мимо_мертвого_кода_3 (переход СРАБОТАЕТ) + короткий_переход_если_меньше skip_jmp_3 + короткий_переход мимо_мертвого_кода_3 +skip_jmp_3: + ; --- МЕРТВЫЙ КОД 3 --- + ; Этот код НЕ должен выполниться (так как jl не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_3 + переместить_имм рдикс, len_msg_dead_3 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_3: + + ; ЧЕТВЁРТЫЙ ПЕРЕХОД: короткий_переход_если_больше + ; Сравниваем 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: + + ; ПЯТЫЙ ПЕРЕХОД: короткий_переход_если_меньше_или_равно (и безусловный) + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0 + сравнить раикс, рбикс + ; Условие jle: ZF=1 ИЛИ SF != OF. ZF=0 (ложь), SF != OF (0 != 0, ложь). jle НЕ сработает. + ; Мы хотим прыгнуть МИМО мертвого кода 5, если jle НЕ сработает (т.е. если rax > rbx). + ; Используем: jle skip_jmp_5 (переход НЕ сработает); jmp мимо_мертвого_кода_5 (переход СРАБОТАЕТ) + короткий_переход_если_меньше_или_равно skip_jmp_5 + короткий_переход мимо_мертвого_кода_5 +skip_jmp_5: + ; --- МЕРТВЫЙ КОД 5 --- + ; Этот код НЕ должен выполниться (так как jle не сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_5 + переместить_имм рдикс, len_msg_dead_5 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_5: + + ; ШЕСТОЙ ПЕРЕХОД: короткий_переход_если_больше_или_равно + ; Сравниваем rax (10) и rbx (5) -> rax > rbx, ZF=0, SF=0, OF=0 + сравнить раикс, рбикс + ; Условие jge: SF=OF. SF=0, OF=0, SF=OF (0=0). jge СРАБОТАЕТ. + ; Мы хотим прыгнуть МИМО мертвого кода 6, если jge сработает (т.е. если rax >= rbx). + короткий_переход_если_больше_или_равно мимо_мертвого_кода_6 + ; --- МЕРТВЫЙ КОД 6 --- + ; Этот код НЕ должен выполниться (так как jge сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_6 + переместить_имм рдикс, len_msg_dead_6 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_6: + + ; СЕДЬМОЙ ПЕРЕХОД: короткий_переход_если_перенос + ; Выполним вычитание, которое вызовет перенос: 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 СРАБОТАЕТ. + ; Мы хотим прыгнуть МИМО мертвого кода 7, если jc сработает (т.е. если был перенос). + короткий_переход_если_перенос мимо_мертвого_кода_7 + ; --- МЕРТВЫЙ КОД 7 --- + ; Этот код НЕ должен выполниться (так как jc сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_7 + переместить_имм рдикс, len_msg_dead_7 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_7: + + ; ВОСЬМОЙ ПЕРЕХОД: короткий_переход_если_нет_переноса + ; Убедимся, что CF=0. Выполним операцию, которая сбросит CF. + сравнить раикс, раикс ; CF = 0 (так как rax - rax = 0, без переноса) + ; Условие jnc: CF=0. CF=0. jnc СРАБОТАЕТ. + ; Мы хотим прыгнуть МИМО мертвого кода 8, если jnc сработает (т.е. если НЕ было переноса). + короткий_переход_если_нет_переноса мимо_мертвого_кода_8 + ; --- МЕРТВЫЙ КОД 8 --- + ; Этот код НЕ должен выполниться (так как jnc сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_8 + переместить_имм рдикс, len_msg_dead_8 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_8: + + ; ДЕВЯТЫЙ ПЕРЕХОД: короткий_переход (безусловный) + ; Просто прыгаем мимо мертвого кода 9. + короткий_переход мимо_мертвого_кода_9 + ; --- МЕРТВЫЙ КОД 9 --- + ; Этот код НЕ должен выполниться (так как jmp сработал) + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_dead_9 + переместить_имм рдикс, len_msg_dead_9 + вызов_системы + ; --------------------- + +мимо_мертвого_кода_9: + + ; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ --- +вывести_сообщение: + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg_success + переместить_имм рдикс, len_msg_success + вызов_системы + + ; --- ЗАВЕРШЕНИЕ --- + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные + ; Перемешиваем строки и константы + ; "Успех!\n" = 5 букв * 2 + 1 (!) + 2 (\n) = 13 байт на содержимое. len = 13 + msg_success: .строка_нуль "Успех!\n" + .константа len_msg_success = 13 + ; "Мертвый код 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 diff --git a/short_jumps/сложный_тест9.квс b/short_jumps/сложный_тест9.квс new file mode 100644 index 0000000..6dcec6e --- /dev/null +++ b/short_jumps/сложный_тест9.квс @@ -0,0 +1,204 @@ +; сложный_тест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 diff --git a/short_jumps/шорт_тест.квс b/short_jumps/шорт_тест.квс new file mode 100644 index 0000000..2e4c22c --- /dev/null +++ b/short_jumps/шорт_тест.квс @@ -0,0 +1,237 @@ +; шорт_тест.квс (обновлённый) +; Исходный файл для тестирования всех коротких условных переходов + +.текст +.глобал _start + +_start: + ; Подготовка: инициализируем регистры для тестирования флагов + переместить_имм раикс, 5 ; rax = 5 + переместить_имм рбикс, 3 ; rbx = 3 + переместить_имм рсикс, 5 ; rcx = 5 (для теста равенства) + + ; --- Тесты для переходов, зависящих от результата cmp --- + ; cmp rax, rbx -> rax(5) > rbx(3) -> SF != OF, ZF = 0 + сравнить раикс, рбикс + + ; Переход если равно (ZF=1) -> не сработает, прыгаем мимо + короткий_переход_если_равно мимо_равно + переместить_имм рдикс, 1 ; Если сюда попали, ZF=0 + переместить_имм рсиай, msg_zf_clear + переместить_имм рдикс, len_msg_zf_clear + переместить_имм раикс, 1 ; write + переместить_имм рдиай, 1 ; stdout + вызов_системы + короткий_переход мимо_равно +мимо_равно: + + ; Переход если не равно (ZF=0) -> сработает + короткий_переход_если_не_ноль мимо_не_равно + переместить_имм рдикс, 1 ; Не должно сработать + переместить_имм рсиай, msg_should_not_print + переместить_имм рдикс, len_msg_should_not_print + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы +мимо_не_равно: + + ; Переход если меньше (SF != OF и SF=1) -> не сработает (SF=0, OF=0) + короткий_переход_если_меньше мимо_меньше + переместить_имм рдикс, 1 ; SF=0 + переместить_имм рсиай, msg_sf_clear + переместить_имм рдикс, len_msg_sf_clear + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + короткий_переход после_меньше +мимо_меньше: + ; Если сработал переход, то SF=1 + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_sf_set + переместить_имм рдикс, len_msg_sf_set + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы +после_меньше: + + ; Переход если больше (ZF=0 и SF=OF) -> сработает (ZF=0, SF=0, OF=0) + короткий_переход_если_больше после_больше + ; Если сюда попали, условие не выполнилось + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_should_not_print + переместить_имм рдикс, len_msg_should_not_print + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + короткий_переход после_еще_одного +после_больше: + + ; Переход если меньше или равно (ZF=1 или SF!=OF) -> не сработает (ZF=0, SF=OF=0) + короткий_переход_если_меньше_или_равно мимо_меньше_равно + ; Условие не выполнилось, ZF=0, SF=OF + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_zf_clear_or_sf_eq_of + переместить_имм рдикс, len_msg_zf_clear_or_sf_eq_of + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + короткий_переход после_еще_одного +мимо_меньше_равно: + ; Условие выполнилось, ZF=1 или SF!=OF + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_zf_set_or_sf_neq_of + переместить_имм рдикс, len_msg_zf_set_or_sf_neq_of + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы +после_еще_одного: + + ; Переход если больше или равно (SF=OF) -> сработает (SF=0, OF=0) + короткий_переход_если_больше_или_равно после_больше_равно + ; Условие не выполнилось, SF != OF + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_sf_neq_of + переместить_имм рдикс, len_msg_sf_neq_of + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + короткий_переход конец_cmp +после_больше_равно: + ; Условие выполнилось, SF = OF + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_sf_eq_of + переместить_имм рдикс, len_msg_sf_eq_of + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы +конец_cmp: + + ; --- Тесты для переходов, зависящих от флага переноса (CF) --- + ; Проверим CF, установив его с помощью вычитания + ; rax = 3, rbx = 5 -> rax - rbx -> CF=1 (т.к. 3 < 5) + переместить_имм раикс, 3 + переместить_имм рбикс, 5 + вычесть рбикс, раикс ; rax = rax - rbx, CF=1 + + ; Переход если перенос (CF=1) -> сработает + короткий_переход_если_перенос после_cf_set + ; Это не должно напечататься + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_should_not_print + переместить_имм рдикс, len_msg_should_not_print + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + короткий_переход после_cf_clear +после_cf_set: + ; CF был установлен + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_cf_set + переместить_имм рдикс, len_msg_cf_set + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + + ; Теперь очистим CF, например, через сравнение 5 и 3 + переместить_имм раикс, 5 + переместить_имм рбикс, 3 + сравнить раикс, рбикс ; rax - rbx, CF=0 (т.к. 5 >= 3) + + ; Переход если нет переноса (CF=0) -> сработает +после_cf_clear: + короткий_переход_если_нет_переноса после_cf_tests + ; Это не должно напечататься + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_should_not_print + переместить_имм рдикс, len_msg_should_not_print + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + короткий_переход после_cf_tests +после_cf_tests: + ; CF был очищен + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_cf_clear + переместить_имм рдикс, len_msg_cf_clear + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + + + ; --- Тесты для переходов, зависящих от ZF (через test) --- + ; test rax, rax -> ZF=0 (rax != 0) + переместить_имм раикс, 10 + проверить раикс, раикс + + ; Переход если ноль (ZF=1) -> не сработает + короткий_переход_если_ноль мимо_test_zf + ; ZF=0 + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_zf_clear + переместить_имм рдикс, len_msg_zf_clear + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + короткий_переход после_test_zf +мимо_test_zf: + ; ZF=1 + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_zf_set + переместить_имм рдикс, len_msg_zf_set + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы +после_test_zf: + + ; test rax, rax -> ZF=1 (rax = 0) + переместить_имм раикс, 0 + проверить раикс, раикс + + ; Переход если ноль (ZF=1) -> сработает + короткий_переход_если_ноль после_test_zf2 + ; Это не должно напечататься + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_should_not_print + переместить_имм рдикс, len_msg_should_not_print + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + короткий_переход после_test_zf2 +после_test_zf2: + ; ZF=1 + переместить_имм рдикс, 1 + переместить_имм рсиай, msg_zf_set + переместить_имм рдикс, len_msg_zf_set + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + + + ; --- Завершение --- + переместить_имм раикс, 60 ; exit + переместить_имм рдиай, 0 ; status + вызов_системы + +.данные +msg_zf_clear: .строка_нуль "ZF=0 (Clear). " +.константа len_msg_zf_clear = 15 +msg_zf_set: .строка_нуль "ZF=1 (Set). " +.константа len_msg_zf_set = 12 +msg_sf_clear: .строка_нуль "SF=0 (Clear). " +.константа len_msg_sf_clear = 14 +msg_sf_set: .строка_нуль "SF=1 (Set). " +.константа len_msg_sf_set = 12 +msg_sf_eq_of: .строка_нуль "SF=OF. " +.константа len_msg_sf_eq_of = 8 +msg_sf_neq_of: .строка_нуль "SF!=OF. " +.константа len_msg_sf_neq_of = 8 +msg_zf_clear_or_sf_eq_of: .строка_нуль "ZF=0 или SF=OF. " +.константа len_msg_zf_clear_or_sf_eq_of = 16 +msg_zf_set_or_sf_neq_of: .строка_нуль "ZF=1 или SF!=OF. " +.константа len_msg_zf_set_or_sf_neq_of = 16 +msg_cf_set: .строка_нуль "CF=1 (Carry Set). " +.константа len_msg_cf_set = 18 +msg_cf_clear: .строка_нуль "CF=0 (No Carry). " +.константа len_msg_cf_clear = 17 +msg_should_not_print: .строка_нуль "ОШИБКА: Это не должно быть напечатано! " +.константа len_msg_should_not_print = 36