Add files via upload

This commit is contained in:
artradeskz 2025-11-08 20:42:59 +03:00 committed by GitHub
parent 9b7fe09c76
commit d8184def66
27 changed files with 8561 additions and 0 deletions

160
jumps/csvhtml.py Normal file
View file

@ -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 = """
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background-color: #f4f7f6; color: #333; margin: 0; padding: 20px; }
.container { max-width: 1400px; margin: 20px auto; background-color: #fff; padding: 25px; border-radius: 8px; box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1); }
h1 { color: #2c3e50; text-align: center; margin-bottom: 25px; }
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { padding: 12px 15px; text-align: left; border-bottom: 1px solid #e0e0e0; vertical-align: top; word-wrap: break-word; }
th { background-color: #34495e; color: #ffffff; font-weight: 600; text-transform: uppercase; font-size: 13px; }
tr:nth-child(even) { background-color: #f8f9fa; }
tr:hover { background-color: #e9ecef; }
a { color: #3498db; text-decoration: none; font-weight: bold; }
a:hover { text-decoration: underline; color: #2980b9; }
.mono { font-family: 'Courier New', Courier, monospace; font-size: 13px; white-space: pre-wrap; }
tr:target { background-color: #fff3cd !important; border: 2px solid #ffeaa7; animation: highlight 2s ease-in-out; }
@keyframes highlight { from { background-color: #ffeaa7; } to { background-color: #fff3cd; } }
</style>
"""
# Начало HTML-документа
html_content = f"""
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{os.path.basename(html_file_path)}</title>
{css_style}
</head>
<body>
<div class="container">
<h1>Анализ дизассемблерного листинга: {os.path.basename(csv_file_path)}</h1>
<table>
<thead><tr>
"""
for header in headers:
html_content += f"<th>{header}</th>\n"
html_content += "</tr></thead><tbody>\n"
# Добавляем строки таблицы
for row in rows:
address = row.get('адрес', '').strip()
target_address = row.get('целевой_адрес', '').strip()
link_html = target_address
if target_address:
link_html = f'<a href="#{target_address}">{target_address}</a>'
# Присваиваем id каждой строке на основе ее адреса
row_id = address if address else ''
html_content += f'<tr id="{row_id}">\n'
html_content += f'<td class="mono">{address}</td>\n'
html_content += f'<td class="mono">{row.get("байт", "")}</td>\n'
html_content += f'<td class="mono">{link_html}</td>\n'
html_content += f'<td>{row.get("исходная_команда", "")}</td>\n'
html_content += "</tr>\n"
html_content += "</tbody></table></div></body></html>"
# Запись 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()

View file

@ -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()

653
jumps/kvs_5.py Normal file
View file

@ -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('<Q', imm))
elif 8 <= reg <= 15:
code.extend(b'\x49')
code.append(0xB8 + (reg - 8))
code.extend(struct.pack('<Q', imm))
else:
raise ValueError("Недопустимый регистр в '" + mnemonic + "'")
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"]
imm = parse_operand(operands[1])
if -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('<i', imm))
else:
raise ValueError("Непосредственное значение слишком велико для сравнения: " + str(imm))
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('<i', offset))
elif itype == "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 + 6)
if offset < -0x80000000 or offset > 0x7FFFFFFF:
raise ValueError("Цель условного перехода слишком далеко: " + str(offset))
code.extend(struct.pack('<i', offset))
# === НОВОЕ: короткие переходы ===
elif itype == "short_jmp":
if len(operands) != 1:
raise ValueError(error_invalid_operand_count(mnemonic, 1, len(operands)))
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(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('<IIQQQQQQ',
p_type, p_flags,
p_offset, p_vaddr, p_vaddr,
p_filesz, p_memsz,
PAGE_SIZE
)
ph0 = phdr(1, 4, 0, elf_base_vaddr, elf_header_size + ph_num * ph_size, PAGE_SIZE)
ph1 = phdr(1, 5, offset_text, vaddr_text, len(text), align_up(len(text), PAGE_SIZE))
ph2 = phdr(1, 6, offset_data, vaddr_data, len(data), align_up(len(data), PAGE_SIZE))
phdrs = ph0 + ph1 + ph2
elf_data[elf_header_size : elf_header_size + len(phdrs)] = phdrs
elf_data[offset_text : offset_text + len(text)] = text
elf_data[offset_data : offset_data + len(data)] = data
elf_data[offset_comment : offset_comment + len(comment)] = comment
elf_data[shstrtab_offset : shstrtab_offset + shstrtab_size] = shstrtab_content
def shdr(name_idx, sh_type, flags, addr, offset, size, addralign=1):
return struct.pack('<IIQQQQIIQQ',
name_idx, sh_type, flags, addr, offset, size,
0, 0, addralign, 0
)
sh0 = shdr(0, 0, 0, 0, 0, 0)
sh1 = shdr(1, 1, 6, vaddr_text, offset_text, len(text), 16)
sh2 = shdr(7, 1, 3, vaddr_data, offset_data, len(data), 8)
sh3 = shdr(13, 1, 0, 0, offset_comment, len(comment), 1)
sh4 = shdr(22, 3, 0, 0, shstrtab_offset, shstrtab_size, 1)
shdrs = sh0 + sh1 + sh2 + sh3 + sh4
elf_data[shdr_offset : shdr_offset + len(shdrs)] = shdrs
with open(filename, "wb") as f:
f.write(elf_data)
import os
os.chmod(filename, 0o755)
# === Основной запуск ===
if len(sys.argv) != 2:
print("Использование: python kvs_4.py <файл.квс>")
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)

930
jumps/kvs_6.py Normal file
View file

@ -0,0 +1,930 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
kvs_6.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('<Q', imm))
elif 8 <= reg <= 15:
code.extend(b'\x49')
code.append(0xB8 + (reg - 8))
code.extend(struct.pack('<Q', imm))
else:
raise ValueError("Недопустимый регистр в '" + mnemonic + "'")
elif size == 32:
if -0x80000000 <= imm <= 0x7FFFFFFF:
rex = 0x40
if reg >= 8:
rex |= 0x01
if rex != 0x40:
code.append(rex)
code.append(0xC7)
modrm = 0xC0 | (reg & 7)
code.append(modrm)
code.extend(struct.pack('<I', imm & 0xFFFFFFFF))
else:
raise ValueError("32-битное значение вне диапазона")
elif size == 16:
if 0 <= imm <= 0xFFFF:
code.append(0x66)
rex = 0x40
if reg >= 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('<i', imm))
else:
raise ValueError("Непосредственное значение слишком велико для сравнения: " + str(imm))
elif size == 32:
if -128 <= imm <= 127:
rex = 0x40
if reg >= 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('<I', imm & 0xFFFFFFFF))
else:
raise ValueError("32-битное непосредственное значение вне диапазона")
elif size == 16:
if -128 <= imm <= 127:
code.append(0x66)
rex = 0x40
if reg >= 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('<i', offset))
elif itype == "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 + 6)
if offset < -0x80000000 or offset > 0x7FFFFFFF:
raise ValueError("Цель условного перехода слишком далеко: " + str(offset))
code.extend(struct.pack('<i', offset))
elif itype == "short_jmp":
if len(operands) != 1:
raise ValueError(error_invalid_operand_count(mnemonic, 1, len(operands)))
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(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('<IIQQQQQQ',
p_type, p_flags,
p_offset, p_vaddr, p_vaddr,
p_filesz, p_memsz,
PAGE_SIZE
)
ph0 = phdr(1, 4, 0, elf_base_vaddr, elf_header_size + ph_num * ph_size, PAGE_SIZE)
ph1 = phdr(1, 5, offset_text, vaddr_text, len(text), align_up(len(text), PAGE_SIZE))
ph2 = phdr(1, 6, offset_data, vaddr_data, len(data), align_up(len(data), PAGE_SIZE))
phdrs = ph0 + ph1 + ph2
elf_data[elf_header_size : elf_header_size + len(phdrs)] = phdrs
elf_data[offset_text : offset_text + len(text)] = text
elf_data[offset_data : offset_data + len(data)] = data
elf_data[offset_comment : offset_comment + len(comment)] = comment
elf_data[shstrtab_offset : shstrtab_offset + shstrtab_size] = shstrtab_content
def shdr(name_idx, sh_type, flags, addr, offset, size, addralign=1):
return struct.pack('<IIQQQQIIQQ',
name_idx, sh_type, flags, addr, offset, size,
0, 0, addralign, 0
)
sh0 = shdr(0, 0, 0, 0, 0, 0)
sh1 = shdr(1, 1, 6, vaddr_text, offset_text, len(text), 16)
sh2 = shdr(7, 1, 3, vaddr_data, offset_data, len(data), 8)
sh3 = shdr(13, 1, 0, 0, offset_comment, len(comment), 1)
sh4 = shdr(22, 3, 0, 0, shstrtab_offset, shstrtab_size, 1)
shdrs = sh0 + sh1 + sh2 + sh3 + sh4
elf_data[shdr_offset : shdr_offset + len(shdrs)] = shdrs
f_out = open(filename, "wb")
f_out.write(elf_data)
f_out.close()
import os
os.chmod(filename, 0o755)
# === Основной запуск ===
if len(sys.argv) != 2:
print("Использование: python kvs_5.py <файл.квс>")
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)

933
jumps/kvs_7.py Normal file
View file

@ -0,0 +1,933 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
kvs_7.py
КВС - язык программирования
без использования re
(расширенная версия с короткими и длинными переходами и полными регистрами)
(исправленная версия с использованием 32-битной формы для 64-битных регистров в cmp_reg_imm)
"""
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\x84", "type": "jcc"}, # je / jz
"переход_если_меньше": {"code": b"\x0F\x8C", "type": "jcc"}, # jl
"переход_если_больше": {"code": b"\x0F\x8F", "type": "jcc"}, # jg
"переход_если_меньше_или_равно": {"code": b"\x0F\x8E", "type": "jcc"}, # jle
"переход_если_больше_или_равно": {"code": b"\x0F\x8D", "type": "jcc"}, # jge
"переход_если_перенос": {"code": b"\x0F\x82", "type": "jcc"}, # jc
"переход_если_нет_переноса": {"code": b"\x0F\x83", "type": "jcc"}, # jnc
"переход_если_ноль": {"code": b"\x0F\x84", "type": "jcc"}, # jz (дубль JE)
"переход_если_не_ноль": {"code": b"\x0F\x85", "type": "jcc"}, # jnz (дубль JNE)
"вызов_системы": {"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('<Q', imm))
elif 8 <= reg <= 15:
code.extend(b'\x49')
code.append(0xB8 + (reg - 8))
code.extend(struct.pack('<Q', imm))
else:
raise ValueError("Недопустимый регистр в '" + mnemonic + "'")
elif size == 32:
if -0x80000000 <= imm <= 0x7FFFFFFF:
rex = 0x40
if reg >= 8:
rex |= 0x01
if rex != 0x40:
code.append(rex)
code.append(0xC7)
modrm = 0xC0 | (reg & 7)
code.append(modrm)
code.extend(struct.pack('<I', imm & 0xFFFFFFFF))
else:
raise ValueError("32-битное значение вне диапазона")
elif size == 16:
if 0 <= imm <= 0xFFFF:
code.append(0x66)
rex = 0x40
if reg >= 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])
# --- ИЗМЕНЕНИЕ: Всегда используем 32-битную форму для 64-битных регистров, если imm помещается ---
if size == 64:
if -0x80000000 <= imm <= 0x7FFFFFFF:
# Используем 32-битное сравнение (с REX.W для 64-битного регистра)
rex = 0x48
if reg >= 8:
rex |= 0x01
code.append(rex)
code.append(0x81) # cmp r/m64, imm32
modrm = 0xF8 | (reg & 7)
code.append(modrm)
code.extend(struct.pack('<i', imm)) # imm32 sign-extended
else:
raise ValueError("Непосредственное значение слишком велико для сравнения: " + str(imm))
elif size == 32:
if -128 <= imm <= 127:
rex = 0x40
if reg >= 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('<I', imm & 0xFFFFFFFF))
else:
raise ValueError("32-битное непосредственное значение вне диапазона")
elif size == 16:
if -128 <= imm <= 127:
code.append(0x66)
rex = 0x40
if reg >= 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('<i', offset))
elif itype == "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 + 6)
if offset < -0x80000000 or offset > 0x7FFFFFFF:
raise ValueError("Цель условного перехода слишком далеко: " + str(offset))
code.extend(struct.pack('<i', offset))
elif itype == "short_jmp":
if len(operands) != 1:
raise ValueError(error_invalid_operand_count(mnemonic, 1, len(operands)))
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(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, # 6 байт для REX.W + 0x81 + ModR/M + imm32
"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('<IIQQQQQQ',
p_type, p_flags,
p_offset, p_vaddr, p_vaddr,
p_filesz, p_memsz,
PAGE_SIZE
)
ph0 = phdr(1, 4, 0, elf_base_vaddr, elf_header_size + ph_num * ph_size, PAGE_SIZE)
ph1 = phdr(1, 5, offset_text, vaddr_text, len(text), align_up(len(text), PAGE_SIZE))
ph2 = phdr(1, 6, offset_data, vaddr_data, len(data), align_up(len(data), PAGE_SIZE))
phdrs = ph0 + ph1 + ph2
elf_data[elf_header_size : elf_header_size + len(phdrs)] = phdrs
elf_data[offset_text : offset_text + len(text)] = text
elf_data[offset_data : offset_data + len(data)] = data
elf_data[offset_comment : offset_comment + len(comment)] = comment
elf_data[shstrtab_offset : shstrtab_offset + shstrtab_size] = shstrtab_content
def shdr(name_idx, sh_type, flags, addr, offset, size, addralign=1):
return struct.pack('<IIQQQQIIQQ',
name_idx, sh_type, flags, addr, offset, size,
0, 0, addralign, 0
)
sh0 = shdr(0, 0, 0, 0, 0, 0)
sh1 = shdr(1, 1, 6, vaddr_text, offset_text, len(text), 16)
sh2 = shdr(7, 1, 3, vaddr_data, offset_data, len(data), 8)
sh3 = shdr(13, 1, 0, 0, offset_comment, len(comment), 1)
sh4 = shdr(22, 3, 0, 0, shstrtab_offset, shstrtab_size, 1)
shdrs = sh0 + sh1 + sh2 + sh3 + sh4
elf_data[shdr_offset : shdr_offset + len(shdrs)] = shdrs
f_out = open(filename, "wb")
f_out.write(elf_data)
f_out.close()
import os
os.chmod(filename, 0o755)
# === Основной запуск ===
if len(sys.argv) != 2:
print("Использование: python kvs_7.py <файл.квс>")
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)

936
jumps/kvs_8.py Normal file
View file

@ -0,0 +1,936 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
kvs_8.py
КВС - язык программирования
без использования re
(расширенная версия с короткими и длинными переходами и полными регистрами)
(исправленная версия с использованием 32-битной формы для 64-битных регистров в cmp_reg_imm)
(добавлена команда нет_операции)
"""
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\x84", "type": "jcc"}, # je / jz
"переход_если_меньше": {"code": b"\x0F\x8C", "type": "jcc"}, # jl
"переход_если_больше": {"code": b"\x0F\x8F", "type": "jcc"}, # jg
"переход_если_меньше_или_равно": {"code": b"\x0F\x8E", "type": "jcc"}, # jle
"переход_если_больше_или_равно": {"code": b"\x0F\x8D", "type": "jcc"}, # jge
"переход_если_перенос": {"code": b"\x0F\x82", "type": "jcc"}, # jc
"переход_если_нет_переноса": {"code": b"\x0F\x83", "type": "jcc"}, # jnc
"переход_если_ноль": {"code": b"\x0F\x84", "type": "jcc"}, # jz (дубль JE)
"переход_если_не_ноль": {"code": b"\x0F\x85", "type": "jcc"}, # jnz (дубль JNE)
"вызов_системы": {"code": b"\x0F\x05", "type": "none"},
"переход": {"code": b"\xE9", "type": "jmp"},
# === Команда нет_операции ===
"нет_операции": {"code": b"\x90", "type": "none"},
# === Короткие переходы ===
"короткий_переход": {"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('<Q', imm))
elif 8 <= reg <= 15:
code.extend(b'\x49')
code.append(0xB8 + (reg - 8))
code.extend(struct.pack('<Q', imm))
else:
raise ValueError("Недопустимый регистр в '" + mnemonic + "'")
elif size == 32:
if -0x80000000 <= imm <= 0x7FFFFFFF:
rex = 0x40
if reg >= 8:
rex |= 0x01
if rex != 0x40:
code.append(rex)
code.append(0xC7)
modrm = 0xC0 | (reg & 7)
code.append(modrm)
code.extend(struct.pack('<I', imm & 0xFFFFFFFF))
else:
raise ValueError("32-битное значение вне диапазона")
elif size == 16:
if 0 <= imm <= 0xFFFF:
code.append(0x66)
rex = 0x40
if reg >= 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])
# --- ИЗМЕНЕНИЕ: Всегда используем 32-битную форму для 64-битных регистров, если imm помещается ---
if size == 64:
if -0x80000000 <= imm <= 0x7FFFFFFF:
# Используем 32-битное сравнение (с REX.W для 64-битного регистра)
rex = 0x48
if reg >= 8:
rex |= 0x01
code.append(rex)
code.append(0x81) # cmp r/m64, imm32
modrm = 0xF8 | (reg & 7)
code.append(modrm)
code.extend(struct.pack('<i', imm)) # imm32 sign-extended
else:
raise ValueError("Непосредственное значение слишком велико для сравнения: " + str(imm))
elif size == 32:
if -128 <= imm <= 127:
rex = 0x40
if reg >= 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('<I', imm & 0xFFFFFFFF))
else:
raise ValueError("32-битное непосредственное значение вне диапазона")
elif size == 16:
if -128 <= imm <= 127:
code.append(0x66)
rex = 0x40
if reg >= 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('<i', offset))
elif itype == "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 + 6)
if offset < -0x80000000 or offset > 0x7FFFFFFF:
raise ValueError("Цель условного перехода слишком далеко: " + str(offset))
code.extend(struct.pack('<i', offset))
elif itype == "short_jmp":
if len(operands) != 1:
raise ValueError(error_invalid_operand_count(mnemonic, 1, len(operands)))
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(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, # 6 байт для REX.W + 0x81 + ModR/M + imm32
"jmp": 5,
"jcc": 6,
"none": lambda: len(instr_info["code"]), # Используем длину кода для "none" инструкций
"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('<IIQQQQQQ',
p_type, p_flags,
p_offset, p_vaddr, p_vaddr,
p_filesz, p_memsz,
PAGE_SIZE
)
ph0 = phdr(1, 4, 0, elf_base_vaddr, elf_header_size + ph_num * ph_size, PAGE_SIZE)
ph1 = phdr(1, 5, offset_text, vaddr_text, len(text), align_up(len(text), PAGE_SIZE))
ph2 = phdr(1, 6, offset_data, vaddr_data, len(data), align_up(len(data), PAGE_SIZE))
phdrs = ph0 + ph1 + ph2
elf_data[elf_header_size : elf_header_size + len(phdrs)] = phdrs
elf_data[offset_text : offset_text + len(text)] = text
elf_data[offset_data : offset_data + len(data)] = data
elf_data[offset_comment : offset_comment + len(comment)] = comment
elf_data[shstrtab_offset : shstrtab_offset + shstrtab_size] = shstrtab_content
def shdr(name_idx, sh_type, flags, addr, offset, size, addralign=1):
return struct.pack('<IIQQQQIIQQ',
name_idx, sh_type, flags, addr, offset, size,
0, 0, addralign, 0
)
sh0 = shdr(0, 0, 0, 0, 0, 0)
sh1 = shdr(1, 1, 6, vaddr_text, offset_text, len(text), 16)
sh2 = shdr(7, 1, 3, vaddr_data, offset_data, len(data), 8)
sh3 = shdr(13, 1, 0, 0, offset_comment, len(comment), 1)
sh4 = shdr(22, 3, 0, 0, shstrtab_offset, shstrtab_size, 1)
shdrs = sh0 + sh1 + sh2 + sh3 + sh4
elf_data[shdr_offset : shdr_offset + len(shdrs)] = shdrs
f_out = open(filename, "wb")
f_out.write(elf_data)
f_out.close()
import os
os.chmod(filename, 0o755)
# === Основной запуск ===
if len(sys.argv) != 2:
print("Использование: python kvs_7.py <файл.квс>")
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)

View file

@ -0,0 +1,124 @@
;длин_тест0.квс
; Тест: один длинный переход и один мусорный сегмент
.текст
.глобал _start
_start:
; Инициализация регистра
переместить_имм раикс, 10 ; rax = 10 (не ноль)
; ПЕРВЫЙ ПЕРЕХОД: переход_если_не_ноль
; ZF=0 (так как rax=10), значит jnz сработает
; Прыгаем к метке 'вывести_сообщение', пропуская мертвый_код_1
переход_если_не_ноль вывести_сообщение
; --- МЕРТВЫЙ КОД 1 ---
; Этот код НЕ должен выполниться
; Добавляем много "мусора", чтобы точно выйти за пределы короткого перехода
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 2
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
; ---------------------
; --- КОД ОШИБКИ (на всякий случай) ---
; Если мы сюда попали, значит переход НЕ сработал (ошибка)
переместить_имм раикс, 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

View file

@ -0,0 +1,230 @@
; длин_тест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
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
; ---------------------
проверка_2:
; ВТОРОЙ ПЕРЕХОД: переход_если_равно
; Сравниваем rax (10) и rbx (5) -> ZF=0
сравнить раикс, рбикс
; ZF=0, значит je НЕ сработает.
; Мы хотим прыгнуть МИМО мертвого кода 2, если ZF=0 (т.е. когда НЕ равны).
; У нас нет инструкции 'переход_если_не_равно' (jne), но она эквивалентна 'переход_если_не_ноль' (jnz) для флага ZF.
; Однако, у нас есть 'переход_если_равно' (je), который сработает при ZF=1.
; Мы хотим, чтобы переход НЕ срабатывал при ZF=0.
; Поэтому мы используем логику: 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
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_2
переместить_имм рдикс, len_msg_dead_2
вызов_системы
; ---------------------
мимо_мертвого_кода_2:
; --- ВЫВОД ЦЕЛЕВОГО СООБЩЕНИЯ ---
вывести_сообщение:
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_success
переместить_имм рдикс, len_msg_success
вызов_системы
; --- ЗАВЕРШЕНИЕ ---
переместить_имм раикс, 60
переместить_имм рдиай, 0
вызов_системы
.данные
; Перемешиваем строки и константы
msg_success: .строка_нуль "Успех!\n"
.константа len_msg_success = 12 ;
msg_dead_2: .строка_нуль "Мертвый код 2!"
.константа len_msg_dead_2 = 14
msg_dead_1: .строка_нуль "Мертвый код 1!"
.константа len_msg_dead_1 = 14

View file

@ -0,0 +1,175 @@
; длин_тест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 = 12 ; Длина "Успех!\n" в UTF-8 без нулевого байта
; "Мертвый код 3!" = 12 букв * 2 байта (UTF-8) + 1 (!) + 1 (\n от .строка_нуль) = 24 + 2 = 26 байт. len = 25 (без \0)
msg_dead_3: .строка_нуль "Мертвый код 3!"
.константа len_msg_dead_3 = 25 ; Длина "Мертвый код 3!" в UTF-8 без нулевого байта
; "Мертвый код 2!" = 12 букв * 2 байта (UTF-8) + 1 (!) + 1 (\n от .строка_нуль) = 24 + 2 = 26 байт. len = 25 (без \0)
msg_dead_2: .строка_нуль "Мертвый код 2!"
.константа len_msg_dead_2 = 25 ; Длина "Мертвый код 2!" в UTF-8 без нулевого байта
; "Мертвый код 1!" = 12 букв * 2 байта (UTF-8) + 1 (!) + 1 (\n от .строка_нуль) = 24 + 2 = 26 байт. len = 25 (без \0)
msg_dead_1: .строка_нуль "Мертвый код 1!"
.константа len_msg_dead_1 = 25 ; Длина "Мертвый код 1!" в UTF-8 без нулевого байта

View file

@ -0,0 +1,196 @@
; длин_тест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 (!) + 1 (\n от .строка_нуль) = 10 + 2 = 12 байт. len = 12
msg_success: .строка_нуль "Успех!\n"
.константа len_msg_success = 12
; "Мертвый код 4!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_4: .строка_нуль "Мертвый код 4!"
.константа len_msg_dead_4 = 19
; "Мертвый код 3!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_3: .строка_нуль "Мертвый код 3!"
.константа len_msg_dead_3 = 19
; "Мертвый код 2!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_2: .строка_нуль "Мертвый код 2!"
.константа len_msg_dead_2 = 19
; "Мертвый код 1!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_1: .строка_нуль "Мертвый код 1!"
.константа len_msg_dead_1 = 19

View file

@ -0,0 +1,260 @@
; длин_тест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 (!) + 1 (\n от .строка_нуль) = 10 + 2 = 12 байт. len = 12
msg_success: .строка_нуль "Успех!\n"
.константа len_msg_success = 12
; "Мертвый код 5!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_5: .строка_нуль "Мертвый код 5!"
.константа len_msg_dead_5 = 19
; "Мертвый код 4!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_4: .строка_нуль "Мертвый код 4!"
.константа len_msg_dead_4 = 19
; "Мертвый код 3!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_3: .строка_нуль "Мертвый код 3!"
.константа len_msg_dead_3 = 19
; "Мертвый код 2!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_2: .строка_нуль "Мертвый код 2!"
.константа len_msg_dead_2 = 19
; "Мертвый код 1!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_1: .строка_нуль "Мертвый код 1!"
.константа len_msg_dead_1 = 19

View file

@ -0,0 +1,280 @@
; длин_тест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 (!) + 1 (\n от .строка_нуль) = 10 + 2 = 12 байт. len = 12
msg_success: .строка_нуль "Успех!\n"
.константа len_msg_success = 12
; "Мертвый код 6!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_6: .строка_нуль "Мертвый код 6!"
.константа len_msg_dead_6 = 19
; "Мертвый код 5!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_5: .строка_нуль "Мертвый код 5!"
.константа len_msg_dead_5 = 19
; "Мертвый код 4!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_4: .строка_нуль "Мертвый код 4!"
.константа len_msg_dead_4 = 19
; "Мертвый код 3!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_3: .строка_нуль "Мертвый код 3!"
.константа len_msg_dead_3 = 19
; "Мертвый код 2!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_2: .строка_нуль "Мертвый код 2!"
.константа len_msg_dead_2 = 19
; "Мертвый код 1!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт. len = 19
msg_dead_1: .строка_нуль "Мертвый код 1!"
.константа len_msg_dead_1 = 19

View file

@ -0,0 +1,374 @@
; длин_тест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
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
; ---------------------
проверка_2:
; ВТОРОЙ ПЕРЕХОД: переход_если_равно (и безусловный)
; Сравниваем 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

View file

@ -0,0 +1,396 @@
; длин_тест7.квс
; Тест: восемь длинных переходов и восемь мусорных сегментов
.текст
.глобал _start
_start:
; Инициализация регистров
переместить_имм раикс, 10 ; rax = 10
переместить_имм рбикс, 5 ; rbx = 5
переместить_имм рсикс, 10 ; rcx = 10 (для проверки ZF в jz)
; ПЕРВЫЙ ПЕРЕХОД: переход_если_не_ноль
; ZF=0 (так как rax=10), значит jnz сработает
; Прыгаем к метке 'проверка_2', пропуская мертвый_код_1
; Добавляем "мусор", чтобы точно выйти за пределы короткого перехода
переход_если_не_ноль проверка_2
переместить_имм раикс, 1
переместить_имм рдиай, 1
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 2
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
; --- МЕРТВЫЙ КОД 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 (!) + 1 (\n от .строка_нуль) = 12 байт на содержимое. len = 12
msg_success: .строка_нуль "Успех!\n"
.константа len_msg_success = 12
; "Мертвый код 8!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_8: .строка_нуль "Мертвый код 8!"
.константа len_msg_dead_8 = 19
; "Мертвый код 7!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_7: .строка_нуль "Мертвый код 7!"
.константа len_msg_dead_7 = 19
; "Мертвый код 6!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_6: .строка_нуль "Мертвый код 6!"
.константа len_msg_dead_6 = 19
; "Мертвый код 5!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_5: .строка_нуль "Мертвый код 5!"
.константа len_msg_dead_5 = 19
; "Мертвый код 4!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_4: .строка_нуль "Мертвый код 4!"
.константа len_msg_dead_4 = 19
; "Мертвый код 3!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_3: .строка_нуль "Мертвый код 3!"
.константа len_msg_dead_3 = 19
; "Мертвый код 2!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_2: .строка_нуль "Мертвый код 2!"
.константа len_msg_dead_2 = 19
; "Мертвый код 1!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_1: .строка_нуль "Мертвый код 1!"
.константа len_msg_dead_1 = 19

View file

@ -0,0 +1,409 @@
; длин_тест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
переместить_имм рдиай, 2
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 3
переместить_имм рдиай, 3
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 4
переместить_имм рдиай, 4
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 5
переместить_имм рдиай, 5
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 6
переместить_имм рдиай, 6
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 7
переместить_имм рдиай, 7
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 8
переместить_имм рдиай, 8
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 9
переместить_имм рдиай, 9
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 10
переместить_имм рдиай, 10
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 11
переместить_имм рдиай, 11
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 12
переместить_имм рдиай, 12
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 13
переместить_имм рдиай, 13
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 14
переместить_имм рдиай, 14
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
переместить_имм раикс, 15
переместить_имм рдиай, 15
переместить_имм рсиай, msg_dead_1
переместить_имм рдикс, len_msg_dead_1
вызов_системы
; ---------------------
проверка_2:
; ВТОРОЙ ПЕРЕХОД: переход_если_равно (и безусловный)
; Сравниваем 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 (!) + 1 (\n от .строка_нуль) = 10 + 2 = 12 байт на содержимое. len = 12
msg_success: .строка_нуль "Успех!\n"
.константа len_msg_success = 12
; "Мертвый код 9!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_9: .строка_нуль "Мертвый код 9!"
.константа len_msg_dead_9 = 19
; "Мертвый код 8!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_8: .строка_нуль "Мертвый код 8!"
.константа len_msg_dead_8 = 19
; "Мертвый код 7!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_7: .строка_нуль "Мертвый код 7!"
.константа len_msg_dead_7 = 19
; "Мертвый код 6!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_6: .строка_нуль "Мертвый код 6!"
.константа len_msg_dead_6 = 19
; "Мертвый код 5!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_5: .строка_нуль "Мертвый код 5!"
.константа len_msg_dead_5 = 19
; "Мертвый код 4!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_4: .строка_нуль "Мертвый код 4!"
.константа len_msg_dead_4 = 19
; "Мертвый код 3!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_3: .строка_нуль "Мертвый код 3!"
.константа len_msg_dead_3 = 19
; "Мертвый код 2!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_2: .строка_нуль "Мертвый код 2!"
.константа len_msg_dead_2 = 19
; "Мертвый код 1!" = 7 букв * 2 + 4 символа * 1 + 1 (\n от .строка_нуль) = 14 + 4 + 1 = 19 байт на содержимое. len = 19
msg_dead_1: .строка_нуль "Мертвый код 1!"
.константа len_msg_dead_1 = 19

View file

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

View file

@ -0,0 +1,35 @@
.текст
.глобал _start
_start:
; Инициализация: raikc = 1 → пропустить первую строку
; Попробуйте изменить на 0 — тогда обе строки напечатаются
переместить_имм раикс, 1
сравнить_с раикс, 1 ; ← обязательно!
; Если 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"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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