132 lines
8.5 KiB
Plaintext
132 lines
8.5 KiB
Plaintext
|
|
; сложный_тест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
|