Показать страницуИстория страницыСсылки сюдаНаверх Эта страница только для чтения. Вы можете посмотреть её исходный текст, но не можете его изменить. Сообщите администратору, если считаете, что это неправильно. ====== Ветвления ====== ====== Ветвления в ассемблере: архитектуры 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. Примеры кода и пояснения === ==== Безусловный переход ==== <code> JMP somewhere </code> ==== Условный переход и работа флагов ==== <code> 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: </code> **Анализ флагов:** * После '''cmp eax, ebx''': * ZF = 0 (результат не ноль) * SF = 1 (отрицательное) * OF = 0 (переполнения нет) * CF = 1 (был "заём" беззнаково) * '''jg''': требует ZF=0 и SF=OF (1 ≠ 0 -- не равно, перехода нет) * '''jl''': SF ≠ OF? (1 ≠ 0 — переход будет!) ==== Проверка на равенство ==== <code> mov eax, 7 mov ebx, 7 cmp eax, ebx je eq_label ; ZF=1, переход будет jne neq_label ; ZF=0, переход не будет </code> ==== Цикл ==== <code> mov cx, 5 loop_start: ; ... тело цикла loop loop_start </code> ==== Вызов функции ==== <code> call my_function ; ... my_function: ; действия ret </code> ==== Косвенный переход ==== <code> jmp [ebx] ; ebx — адрес новой инструкции </code> ---- ==== 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. Примеры кода и пояснения === ==== Пример: ==== <code> 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 ? </code> * После CMP: * N = 1 (отрицательное) * Z = 0 (не ноль) * V = 0 * C = 0 * BEQ — не сработает (Z=0) * BNE — выполнится (Z=0) * BLT — N ≠ V (1 ≠ 0) — выполнится ==== Вызовы процедур ==== <code> BL myfunc ; вызов с занесением адреса возврата в LR ; ... myfunc: ; ... BX LR ; возврат </code> ==== Табличный переход ==== <code> 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: </code> ---- ==== 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. Пример кода и разбор === ==== Знаковое сравнение ==== <code> li $t0, -2 li $t1, 1 slt $at, $t0, $t1 # $at = ($t0 < $t1) ? 1 : 0 bnez $at, less_label # если $at != 0 — переход будет </code> ==== Вызов функции ==== <code> jal my_func # ... my_func: ; ... jr $ra </code> ==== Табличный переход ==== <code> sll $t1, $a0, 2 la $t2, jumptable addu $t1, $t1, $t2 lw $t3, 0($t1) jr $t3 </code> ---- === 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 $at, $a0, $a1; bnez $at, l | ---- ===== 6. Разбор переходов с анализом флагов (на примере x86, ARM, MIPS) ===== === 6.1. x86: знаковое сравнение === <code> 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 ; равно? </code> **Флаги:** - ZF = 0 (результат не ноль) - SF = 1 (отрицательное) - OF = 0 (нет переполнения) - CF = 1 (беззнаковый "заём") '''JG''' требует ZF=0 и SF=OF: 1 ≠ 0 — перехода НЕ будет. '''JL''' требует SF ≠ OF: 1 ≠ 0 — переход БУДЕТ! --- === 6.2. x86: проверка на равенство === <code> mov eax, 7 mov ebx, 7 cmp eax, ebx je eq_label ; ZF=1 — переход БУДЕТ! jne neq_label ; ZF=0 — перехода не будет </code> --- === 6.3. ARM: сравнение и разбор по флагам === <code> 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? </code> == После CMP: == * N = 1 (отрицательно), V = 0, Z = 0 * BEQ — НЕ сработает; BNE — переход БУДЕТ; BLT — переход БУДЕТ. --- === 6.4. ARM: переполнение === <code> 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, было переполнение — БУДЕТ переход! </code> --- === 6.5. MIPS: ветвление через регистр-посредник === <code> li $t0, -2 li $t1, 1 slt $at, $t0, $t1 # if $t0 < $t1, $at = 1 bnez $at, less_label # если 1 — переход БУДЕТ! </code> --- reverseenengineering/ветвления.txt Последнее изменение: 2025/07/16 21:39 — Lex Войти