====== Ветвления ======
====== Ветвления в ассемблере: архитектуры 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. x86 (Intel) ====
=== 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. ARM ====
=== 3.1. Флаги ===
^ Флаг | Назначение |
| N (Negative) | Результат отрицательный? (MSB=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. MIPS ====
=== 4.1. Нет регистра флагов! ===
Всё ветвление идёт по значению регистров.
^ Инструкция | Что выполняет |
| beq $a, $b, label | Переход, если равны ($a = $b) |
| 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 $t1, 1
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 (BEQ, BNE, BLT и др.) | cmp r0, r1; blt label |
| MIPS | Нет флагов, сравн. в регистре | beq, bne, slt+bnez | slt $at, $a0, $a1; bnez $at, l |
----
===== 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 ; больше? (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 $t0, -2
li $t1, 1
slt $at, $t0, $t1 # if $t0 < $t1, $at = 1
bnez $at, less_label # если 1 — переход БУДЕТ!
---