kvs/short_jumps/сложный_тест1.квс
2025-11-08 13:24:11 +03:00

132 lines
8.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; сложный_тест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