reverseenengineering:ветвления

Это старая версия документа!


Ветвления

Ветвления в ассемблере: архитектуры x86 (Intel), ARM, MIPS

1. Основные функции ветвления в ассемблере

Ветвление (branching) — это переход исполнения программы на другую инструкцию, обычно по условию. Вот основные виды ветвления (на примере x86):

Безусловный переход: :: JMP label Условный переход по флагам: :: Jcc label (JE, JNE, JL, JG и др.) Переход с возвратом: :: CALL label, RET Циклические переходы: :: LOOP label, LOOPE, LOOPNE Косвенные переходы: :: JMP [reg] Табличные переходы: :: через адресацию перехода по таблице (jump table) Прерывания и возврат из них: :: INT N, IRET Желающие подробности по архитектурам — читайте далее.

2.1. Работа флагов

После арифметической/логической операции процессор выставляет флаги в регистре EFLAGS:

Название Описание 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 ; вычитание: -3 - 1 = -4 (0xFFFFFFFCh) jg more_label ; если eax > ebx (signed)? jl less_label ; если eax < ebx (signed)? je equal_label ; если eax == ebx?
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: 

Анализ флагов:

После 'cmp eax, ebx': ZF = 0 (результат не ноль) SF = 1 (отрицательное) OF = 0 (переполнения нет) CF = 1 (был «заём» беззнаково) 'jg': требует ZF=0 и SF=OF (1 ≠ 0 – не равно, перехода нет) 'jl': SF ≠ OF? (1 ≠ 0 — переход будет!) ==== Проверка на равенство ====

 mov eax, 7 mov ebx, 7 cmp eax, ebx je eq_label ; ZF=1, переход будет jne neq_label ; ZF=0, переход не будет 

==== Цикл ====

 mov cx, 5 loop_start: ; ... тело цикла loop loop_start 

==== Вызов функции ====

 call my_function ; ... my_function: ; действия ret 

==== Косвенный переход ====

 jmp [ebx] ; ebx — адрес новой инструкции 

3.1. Флаги

Флаг Назначение N (Negative) Результат отрицательный? (MLSB=1) Z (Zero) Результат 0? C (Carry) Перенос/заём для беззнаковых V (Overflow) Переполнение для знаковых

Инструкции, которые изменяют флаги — обычно с S: 'ADDS', 'SUBS', 'CMP', 'ANDS' и др.

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 ; Z=1 ? BNE label_ne ; Z=0 ? BLT label_lt ; N ≠ V ? 

После CMP:

N = 1 (отрицательное) Z = 0 (не ноль) V = 0 C = 0 BEQ — не сработает (Z=0)

BNE — выполнится (Z=0)

BLT — N ≠ V (1 ≠ 0) — выполнится

==== Вызовы процедур ====

 BL myfunc ; вызов с занесением адреса возврата в LR ; ... myfunc: ; ... BX LR ; возврат 

==== Табличный переход ====

 CMP R0, #3 BHI default LDR PC, [PC, R0, LSL #2] ; PC ← (таблица адресов: case0, case1...)

.word case0 .word case1 .word case2 .word case3

case0: ; ... BX LR

default: 

4.1. Нет регистра флагов!

Всё ветвление идёт по значению регистров.

Инструкция Что выполняет

a , a,b, label | Переход, если равны ( a = a=b) | | bne a , a,b, label | Переход, если не равны | | slt r , r,a, b ∣ b∣r = 1, если a < a<b (signed), иначе 0 | | sltu r , r,a, b ∣ b∣r = 1, если a < a<b (unsigned) | | jal, jr $ra | Вызов/возврат процедуры |

4.2. Пример кода и разбор

==== Знаковое сравнение ====

 li 
t
0
,
−
2
l
i
t0,−2lit1, 1 slt 
a
t
,
at,t0, t1 # at = (
t
0
<
t0<t1) ? 1 : 0 bnez at, less_label # если at != 0 — переход будет 

==== Вызов функции ====

 jal my_func

...
my_func: ; ... jr $ra 

==== Табличный переход ====

 sll 
t
1
,
t1,a0, 2 la 
t
2
,
j
u
m
p
t
a
b
l
e
a
d
d
u
t2,jumptableaddut1, 
t
1
,
t1,t2 lw 
t
3
,
0
(
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<cond> (BEQ, BNE, BLT и др.) cmp r0, r1; blt label MIPS Нет флагов, сравн. в регистре beq, bne, slt+bnez slt a t , at,a0, a 1 ; b n e z a1;bnezat, l

6.1. x86: знаковое сравнение

 mov eax, -3 ; FFFFFFFD mov ebx, 1 ; 00000001 cmp eax, ebx ; -3 - 1 = -4 (FFFFFFFC) jg more_label ; больше? (signed) jl less_label ; меньше? (signed) je equal_label ; равно? 

Флаги:

ZF = 0 (результат не ноль) SF = 1 (отрицательное) OF = 0 (нет переполнения) CF = 1 (беззнаковый «заём») 'JG' требует ZF=0 и SF=OF: 1 ≠ 0 — перехода НЕ будет. 'JL' требует SF ≠ OF: 1 ≠ 0 — переход БУДЕТ!

=== 6.2. x86: проверка на равенство ===

 mov eax, 7 mov ebx, 7 cmp eax, ebx je eq_label ; ZF=1 — переход БУДЕТ! 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 ; Z=1? BNE label_ne ; Z=0? BLT label_lt ; N ≠ V? 
После CMP:

N = 1 (отрицательно), V = 0, Z = 0 BEQ — НЕ сработает; BNE — переход БУДЕТ; BLT — переход БУДЕТ. === 6.4. ARM: переполнение ===

 MOV R2, #0x7FFFFFFF ADD R2, R2, #1 ; R2 = 0x80000000 (отрицательное по знаку) CMP R2, #0 BEQ label_zero ; Z=0 BMI label_negative ; N=1 — БУДЕТ переход! BVS label_o ; V=1, было переполнение — БУДЕТ переход! 

=== 6.5. MIPS: ветвление через регистр-посредник ===

 li 
t
0
,
−
2
l
i
t0,−2lit1, 1 slt 
a
t
,
at,t0, t1 # if t0 < 
t
1
,
t1,at = 1 bnez $at, less_label # если 1 — переход БУДЕТ! 
  • reverseenengineering/ветвления.1752676440.txt.gz
  • Последнее изменение: 2025/07/16 21:34
  • Lex