Unconditional Branching
El segundo tipo de Control Instructions
son las Branching Instructions
, que son instrucciones generales que nos permiten hacer un jump
a cualquier punto del programa si se cumple una condición específica. Primero, hablemos de la instrucción de branching más básica: jmp
, que siempre saltará a una ubicación de manera incondicional.
JMP loopFib
La instrucción jmp
salta el programa a la etiqueta o ubicación especificada en su operando para que la ejecución del programa continúe allí. Una vez que la ejecución del programa se dirige a otra ubicación, continuará procesando las instrucciones desde ese punto. Si quisiéramos saltar temporalmente a un punto y luego regresar al punto de llamada original, usaríamos funciones, las cuales discutiremos en la siguiente sección.
La instrucción básica jmp
es incondicional, lo que significa que siempre saltará a la ubicación especificada, independientemente de las condiciones. Esto contrasta con las instrucciones de Conditional Branching
, que solo saltan si se cumple una condición específica, las cuales veremos a continuación.
Instruction | Description | Example |
---|---|---|
jmp |
Salta a la etiqueta, dirección o ubicación especificada | jmp loop |
Probemos usar jmp
en nuestro programa fib.s
, y veamos cómo cambiaría el flujo de ejecución. En lugar de hacer un bucle de regreso a loopFib
, hagamos un jmp
allí en su lugar. Así, nuestro código final es:
global _start
section .text
_start:
xor rax, rax ; initialize rax to 0
xor rbx, rbx ; initialize rbx to 0
inc rbx ; increment rbx to 1
mov rcx, 10
loopFib:
add rax, rbx ; get the next number
xchg rax, rbx ; swap values
jmp loopFib
Ahora, armemos nuestro código y ejecutémoslo con gdb
. Una vez más, pondremos un b loopFib
y veremos cómo cambia:
$ ./assembler.sh fib.s -g
gef➤ b loopFib
Breakpoint 1 at 0x40100e
gef➤ r
───────────────────────────────────────────────────────────────────────────────────── registers ────
$rbx : 0x1
$rcx : 0xa
$rcx : 0xa
───────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x1
$rbx : 0x1
$rcx : 0xa
───────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x1
$rbx : 0x2
$rcx : 0xa
───────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x2
$rbx : 0x3
$rcx : 0xa
───────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x3
$rbx : 0x5
$rcx : 0xa
───────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x5
$rbx : 0x8
$rcx : 0xa
Presionamos c
varias veces para permitir que el programa salte múltiples veces de regreso a loopFib
. Como podemos ver, el programa sigue realizando la misma función y calculando correctamente la Secuencia de Fibonacci. Sin embargo, la diferencia principal con el bucle es que 'rcx' no está decreciendo. Esto se debe a que una instrucción jmp
no considera rcx
como un contador (como lo hace loop
), por lo que no lo decrementará automáticamente.
Eliminemos nuestro punto de interrupción con del 1
y presionemos c
para ver hasta dónde se ejecutará el programa:
gef➤ info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000040100e <loopFib>
breakpoint already hit 6 times
gef➤ del 1
gef➤ c
Continuing.
Program received signal SIGINT, Interrupt.
0x000000000040100e in loopFib ()
───────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x2e02a93188557fa9
$rbx : 0x903b4b15ce8cedf0
$rcx : 0xa
Notamos que el programa siguió ejecutándose hasta que presionamos ctrl+c
después de unos segundos para matarlo, en cuyo punto el número de Fibonacci llegó a 0x903b4b15ce8cedf0
(que es un número enorme). Esto se debe a la instrucción incondicional jmp
, que sigue saltando de regreso a loopFib
para siempre, ya que no hay una condición específica que lo restrinja. Esto es similar a un bucle (while true)
.
Por esta razón, el Branching incondicional se usa generalmente en casos donde siempre necesitamos saltar, y no es adecuado para bucles, ya que se repetirá para siempre. Para detener los saltos cuando se cumpla una condición específica, usaremos Conditional Branching
en nuestros próximos pasos.