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