Различия
Показаны различия между двумя версиями страницы.
| Следующая версия | Предыдущая версия | ||
| reverseenengineering:ветвления [2025/06/23 23:56] – создано Lex | reverseenengineering:ветвления [2025/07/16 21:39] (текущий) – Lex | ||
|---|---|---|---|
| Строка 1: | Строка 1: | ||
| ====== Ветвления ====== | ====== Ветвления ====== | ||
| + | ====== Ветвления в ассемблере: | ||
| + | |||
| + | === 1. Основные функции ветвления в ассемблере === | ||
| + | |||
| + | Ветвление (branching) — это переход исполнения программы на другую инструкцию, | ||
| + | |||
| + | * **Безусловный переход**: | ||
| + | * **Условный переход по флагам**: | ||
| + | * **Переход с возвратом**: | ||
| + | * **Циклические переходы**: | ||
| + | * **Косвенные переходы**: | ||
| + | * **Табличные переходы**: | ||
| + | * **Прерывания и возврат из них**: :: '' | ||
| + | |||
| + | Желающие подробности по архитектурам — читайте далее. | ||
| + | |||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== 2. x86 (Intel) ==== | ||
| + | |||
| + | === 2.1. Работа флагов === | ||
| + | |||
| + | После арифметической/ | ||
| + | |||
| + | ^ Название | Описание | | ||
| + | | ZF (Zero Flag) | Результат 0? (1 если да) | | ||
| + | | SF (Sign Flag) | Знак результата (1=минус) | | ||
| + | | CF (Carry Flag) | Перенос (важно при беззнаковых) | | ||
| + | | OF (Overflow Flag) | Переполнение (важно при знаковых) | | ||
| + | | PF (Parity Flag) | Четность (не часто используется) | | ||
| + | |||
| + | === 2.2. Основные команды ветвления === | ||
| + | |||
| + | ^ Инструкция | Условие | Обозначение | | ||
| + | | JE/JZ | ZF = 1 | Равно ("Jump if Equal" | ||
| + | | JNE/JNZ | ZF = 0 | Не равно | | ||
| + | | JL | (SF ≠ OF) | Меньше (signed) | | ||
| + | | JLE | (ZF=1 or SF ≠ OF) | Меньше или равно (signed) | | ||
| + | | JG | (ZF=0 and SF=OF) | Больше (signed) | | ||
| + | | JGE | (SF=OF) | Больше или равно (signed) | | ||
| + | | JB | CF = 1 | Меньше (unsigned) | | ||
| + | | JBE | CF=1 or ZF=1 | Меньше или равно (unsigned) | | ||
| + | | JA | (CF=0 and ZF=0) | Больше (unsigned) | | ||
| + | | JAE | CF = 0 | Больше или равно (unsigned) | | ||
| + | | CALL, RET | | Вызов и возврат процедуры | | ||
| + | | JMP [рег] | | Косвенный переход | | ||
| + | |||
| + | === 2.3. Примеры кода и пояснения === | ||
| + | |||
| + | ==== Безусловный переход ==== | ||
| + | < | ||
| + | JMP somewhere | ||
| + | </ | ||
| + | |||
| + | ==== Условный переход и работа флагов ==== | ||
| + | |||
| + | < | ||
| + | mov eax, -3 ; eax = FFFFFFFDh (32-битный -3) | ||
| + | mov ebx, 1 ; ebx = 00000001h | ||
| + | cmp eax, ebx ; вычитание: | ||
| + | jg | ||
| + | jl | ||
| + | je | ||
| + | |||
| + | mov ecx, 123 | ||
| + | jmp end | ||
| + | |||
| + | more_label: | ||
| + | mov ecx, 1 | ||
| + | jmp end | ||
| + | |||
| + | less_label: | ||
| + | mov ecx, 2 | ||
| + | jmp end | ||
| + | |||
| + | equal_label: | ||
| + | mov ecx, 3 | ||
| + | |||
| + | end: | ||
| + | </ | ||
| + | |||
| + | **Анализ флагов: | ||
| + | |||
| + | * После ''' | ||
| + | * ZF = 0 (результат не ноль) | ||
| + | * SF = 1 (отрицательное) | ||
| + | * OF = 0 (переполнения нет) | ||
| + | * CF = 1 (был " | ||
| + | * ''' | ||
| + | * ''' | ||
| + | |||
| + | |||
| + | ==== Проверка на равенство ==== | ||
| + | < | ||
| + | mov eax, 7 | ||
| + | mov ebx, 7 | ||
| + | cmp eax, ebx | ||
| + | je eq_label | ||
| + | jne neq_label ; ZF=0, переход не будет | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Цикл ==== | ||
| + | < | ||
| + | mov cx, 5 | ||
| + | loop_start: | ||
| + | ; ... тело цикла | ||
| + | loop loop_start | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Вызов функции ==== | ||
| + | < | ||
| + | call my_function | ||
| + | ; ... | ||
| + | my_function: | ||
| + | ; действия | ||
| + | ret | ||
| + | </ | ||
| + | |||
| + | ==== Косвенный переход ==== | ||
| + | < | ||
| + | jmp [ebx] ; ebx — адрес новой инструкции | ||
| + | </ | ||
| + | |||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== 3. ARM ==== | ||
| + | |||
| + | === 3.1. Флаги === | ||
| + | |||
| + | ^ Флаг | Назначение | | ||
| + | | N (Negative) | Результат отрицательный? | ||
| + | | Z (Zero) | Результат 0? | | ||
| + | | C (Carry) | Перенос/ | ||
| + | | V (Overflow) | Переполнение для знаковых | | ||
| + | |||
| + | Инструкции, | ||
| + | |||
| + | === 3.2. Ветвления по суффиксам === | ||
| + | |||
| + | Любая инструкция ветвления (и почти любая другая) может иметь суффикс условия: | ||
| + | |||
| + | ^ Суффикс | Условие | Описание | | ||
| + | | EQ | Z=1 | Равно | | ||
| + | | NE | Z=0 | Не равно | | ||
| + | | LT | N ≠ V | Меньше (signed) | | ||
| + | | GT | Z=0 и N=V | Больше (signed) | | ||
| + | | GE | N=V | Больше или равно (signed) | | ||
| + | | LE | Z=1 или N ≠ V | Меньше или равно (signed) | | ||
| + | | CS/HS | C=1 | Беззнаково >= | | ||
| + | | CC/LO | C=0 | Беззнаково < | | ||
| + | |||
| + | === 3.3. Примеры кода и пояснения === | ||
| + | |||
| + | ==== Пример: | ||
| + | < | ||
| + | MOV R0, #5 | ||
| + | MOV R1, #8 | ||
| + | CMP R0, R1 ; R0 - R1 = -3 (Negative) | ||
| + | BEQ label_eq | ||
| + | BNE label_ne | ||
| + | BLT label_lt | ||
| + | </ | ||
| + | |||
| + | * После CMP: | ||
| + | * N = 1 (отрицательное) | ||
| + | * Z = 0 (не ноль) | ||
| + | * V = 0 | ||
| + | * C = 0 | ||
| + | |||
| + | * BEQ — не сработает (Z=0) | ||
| + | * BNE — выполнится (Z=0) | ||
| + | * BLT — N ≠ V (1 ≠ 0) — выполнится | ||
| + | |||
| + | ==== Вызовы процедур ==== | ||
| + | < | ||
| + | BL myfunc | ||
| + | ; ... | ||
| + | myfunc: | ||
| + | ; ... | ||
| + | BX LR ; возврат | ||
| + | </ | ||
| + | |||
| + | ==== Табличный переход ==== | ||
| + | < | ||
| + | CMP R0, #3 | ||
| + | BHI default | ||
| + | LDR PC, [PC, R0, LSL #2] ; PC ← (таблица адресов: | ||
| + | |||
| + | .word case0 | ||
| + | .word case1 | ||
| + | .word case2 | ||
| + | .word case3 | ||
| + | |||
| + | case0: | ||
| + | ; ... | ||
| + | BX LR | ||
| + | |||
| + | default: | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== 4. MIPS ==== | ||
| + | |||
| + | === 4.1. Нет регистра флагов! === | ||
| + | |||
| + | Всё ветвление идёт по значению регистров. | ||
| + | |||
| + | ^ Инструкция | Что выполняет | | ||
| + | | beq $a, $b, label | Переход, | ||
| + | | bne $a, $b, label | Переход, | ||
| + | | slt $r, $a, $b | $r = 1, если $a < $b (signed), иначе 0 | | ||
| + | | sltu $r, $a, $b | $r = 1, если $a < $b (unsigned) | | ||
| + | | jal, jr $ra | Вызов/ | ||
| + | |||
| + | |||
| + | === 4.2. Пример кода и разбор === | ||
| + | |||
| + | ==== Знаковое сравнение ==== | ||
| + | < | ||
| + | li $t0, -2 | ||
| + | li | ||
| + | slt $at, $t0, $t1 # $at = ($t0 < $t1) ? 1 : 0 | ||
| + | bnez $at, less_label # если $at != 0 — переход будет | ||
| + | </ | ||
| + | |||
| + | ==== Вызов функции ==== | ||
| + | < | ||
| + | jal my_func | ||
| + | # ... | ||
| + | my_func: | ||
| + | ; ... | ||
| + | jr $ra | ||
| + | </ | ||
| + | |||
| + | ==== Табличный переход ==== | ||
| + | < | ||
| + | sll $t1, $a0, 2 | ||
| + | la $t2, jumptable | ||
| + | addu $t1, $t1, $t2 | ||
| + | lw $t3, 0($t1) | ||
| + | jr $t3 | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | === 5. Краткий итог сравнения ветвлений === | ||
| + | |||
| + | ^ Архитектура | Флаги/ | ||
| + | |-------------|-------------------------------|-----------------------------------------|--------------------| | ||
| + | | x86 | EFLAGS (ZF, SF, OF, CF, PF) | JE, JNE, JL, JG, JA, JB... | cmp ax, bx; jl label | | ||
| + | | ARM | CPSR (N, Z, C, V) | B< | ||
| + | | MIPS | Нет флагов, | ||
| + | |||
| + | |||
| + | |||
| + | ---- | ||
| + | |||
| + | ===== 6. Разбор переходов с анализом флагов (на примере x86, ARM, MIPS) ===== | ||
| + | |||
| + | === 6.1. x86: знаковое сравнение === | ||
| + | |||
| + | < | ||
| + | mov eax, -3 ; FFFFFFFD | ||
| + | mov ebx, 1 ; 00000001 | ||
| + | cmp eax, ebx ; -3 - 1 = -4 (FFFFFFFC) | ||
| + | jg more_label | ||
| + | jl less_label | ||
| + | je equal_label | ||
| + | </ | ||
| + | |||
| + | **Флаги: | ||
| + | - ZF = 0 (результат не ноль) | ||
| + | - SF = 1 (отрицательное) | ||
| + | - OF = 0 (нет переполнения) | ||
| + | - CF = 1 (беззнаковый " | ||
| + | |||
| + | ''' | ||
| + | ''' | ||
| + | |||
| + | --- | ||
| + | |||
| + | === 6.2. x86: проверка на равенство === | ||
| + | < | ||
| + | mov eax, 7 | ||
| + | mov ebx, 7 | ||
| + | cmp eax, ebx | ||
| + | je eq_label | ||
| + | jne neq_label ; ZF=0 — перехода не будет | ||
| + | </ | ||
| + | |||
| + | --- | ||
| + | |||
| + | === 6.3. ARM: сравнение и разбор по флагам === | ||
| + | |||
| + | < | ||
| + | MOV R0, #5 | ||
| + | MOV R1, #8 | ||
| + | CMP R0, R1 ; результат -3, N=1, Z=0, V=0 | ||
| + | BEQ label_eq | ||
| + | BNE label_ne | ||
| + | BLT label_lt | ||
| + | </ | ||
| + | |||
| + | == После CMP: == | ||
| + | * N = 1 (отрицательно), | ||
| + | * BEQ — НЕ сработает; | ||
| + | |||
| + | --- | ||
| + | |||
| + | === 6.4. ARM: переполнение === | ||
| + | < | ||
| + | MOV R2, #0x7FFFFFFF | ||
| + | ADD R2, R2, #1 ; R2 = 0x80000000 (отрицательное по знаку) | ||
| + | CMP R2, #0 | ||
| + | BEQ label_zero | ||
| + | BMI label_negative | ||
| + | BVS label_o | ||
| + | </ | ||
| + | |||
| + | --- | ||
| + | |||
| + | === 6.5. MIPS: ветвление через регистр-посредник === | ||
| + | < | ||
| + | li $t0, -2 | ||
| + | li | ||
| + | slt $at, $t0, $t1 # if $t0 < $t1, $at = 1 | ||
| + | bnez $at, less_label # если 1 — переход БУДЕТ! | ||
| + | </ | ||
| + | |||
| + | --- | ||
| + | |||