Saltar a contenido

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.