Skip to Content

LEGv8

LEGv8 es un conjunto de instrucciones. Es una versión simplificada y un subconjunto de ARMv8.

Convención de registros

  • X0 - X7: Argumentos de entrada/salida de funciones.
  • X8: Resultado indirecto de localización de registro.
  • X9 - X15: Registros temporales.
  • X16 - X17: Sobreescrito por el sistema como scratch register.
  • X18: Registro de uso especial del OS o temporal
  • X19 - X27: Registros de uso general.
  • X28: Puntero a stack.
  • X29: Puntero a frame.
  • X30: Registro de enlace (link register).
  • XZR: Valor constante 0.

Instrucciones

  • ADD: Suma de registros
  • ADDI: Suma con valor constante
  • SUB: Resta de registros
  • SUBI: Resta con valor constante
  • AND: Operación AND entre registros
  • ANDI: Operación AND con valor constante
  • ORR: Operación OR entre registros
  • EOR: Operación XOR entre registros
  • ORRI: Operación OR con valor constante
  • LSL: Recibe una constante #cy recibe un registro para multiplicarlo por 2^c.
    Desplaza a la izquierda el registro X1 #c veces y lo almacena en X2.
  • LSR: Recibe una constante c, desplaza a la derecha el registro X1 #c veces y lo almacena en X2.
  • LDUR: Copia al registro X1 el contenido en la posición de memoria direccionada por X2 sumado a la constante #c (memoria doubleword)
  • STUR : Copia el contenido del registro X1 en la posición de memoria direccionada por X2 sumado a la constante #c (memoria doubleword)
  • LDURSW: Lo mismo que LDUR (memoria word)
  • STURSW: Lo mismo que STUR (memoria word)
  • LDURB: Lo mismo que LDUR (memoria byte)
  • STURB: Lo mismo que STUR (memoria byte)
  • MOVZ: Mueve un valor inmediato a un registro (cero extendido)
  • MOVK: Mueve un valor inmediato a un registro y lo combina con el contenido del registro.

Operaciones

Operaciones inmediatas (valores constantes)

// Ejemplo de código C f = g + 5;

Sean g => X21 y f => X19, la instrucción se traduce a:

ADDI X19, X21, #5

Operaciones en registros

Las operaciones en registros se hacen de la siguiente forma

// Ejemplo de código C f = (g + h) - (i + j);

Solo se puede operar sobre dos registros a la vez, por lo que se requieren valores temporales:

ADD X9, X21, X22 // g + h ADD X10, X22, X23 // i + j SUB X19, X9, X10 // f = (g + h) - (i + j)

Operaciones en memoria

Operar en datos almacenados en memoria es más lento que operar en registros, ya que requieren más instrucciones:

// Ejemplo de código C a[12] = h + a[8];

Sean h => X21 y a => X22, la instrucción se traduce a:

LDUR X9, [X22, #64] ADD X9, X21, X9 STUR X9, [X22, #96]

Cada elemento de memoria es de \(8\) bits, para obtener los \(64\) bits necesarios de cada elemento del arreglo a hay que usar un offset de \(n * 8\) bits.

Ejercicios resueltos - Operaciones

Escribir las secuencias de assembler LEGv8 en base al código C:

1.

// A) f = g + h + i + j; // B) f = g + (h + 5); // C) f = (g + h) + (i + j);

Para este ejercicio, se asignan a las variables f, g, h, i, j los registros X0, X1, X2, X3, X4, respectivamente:

// A) ADD X0, X1, X2 ADD X0, X0, X3 ADD X0, X0, X4 // B) ADD X0, X0, X1 ADDI X0, X2, #5 // C) ADD X9, X1, X2 ADD X10, X3, X4 ADD X0, X9, X10

2.

// A) f = -g - f; // B) f = g + (-f - 5);

Para este ejercicio, se asignan a las variables f, g los registros X0, X1, respectivamente:

// A) ADD X0, X1, X0 SUB X0, XZR, X0 // B) ADDI X0, X0, #5 SUB X0, X1, X0

3.

// A) f = -g - a[4]; // B) b[8] = a[i - j];

Para este ejercicio, se asignan a las variables f, g, i, j los registros X0, X1, X2, X3, respectivamente.
La dirección base de los arrays a, b se almacenan en los registros X6, X7

// A) LDUR X0, [X6, #32] // f = a[4] ADD X0, X0, X1 // f = (a[4]) + g SUB X0, XZR, X0 // f = 0 - (a[4] + g) // B) SUB X9, X2, X3 // X9 = i - j LSL X9, X9, #3 // X9 = (i - j) * 8 ADD X10, X6, X9 // X10 = &a + [(i - j) * 8] LDUR X11, [X10, #0] // X11 = a[i - j] STUR X11, [X7, #64] // b[8] = a[i - j]

4.

Usar MOVZ, MOVK para cargar los registros:

{X0 = 0x1234000000000000} {X1 = 0xBBB0000000000AAA} {X2 = 0xA0A0B1B10000C2C2} {X3 = 0x0123456789ABCDEF}
MOVZ X0, 0x1234, LSL 48 // 0x1234000000000000 MOVZ X1, 0xBBB, LSL 52 // 0xBBB0000000000000 MOVK X1, 0xAAA, LSL 00 // 0xBBB0000000000AAA MOVZ X2, 0xA0A0, LSL 48 // 0xA0A0000000000000 MOVK X2, 0xB1B1, LSL 32 // 0xA0A00000B1B10000 MOVK X2, 0xC2C2, LSL 00 // 0xA0A0B1B10000C2C2 MOVZ X3, 0x0123, LSL 48 // 0x0123000000000000 MOVK X3, 0x4567, LSL 32 // 0x0123456700000000 MOVK X3, 0x89AB, LSL 16 // 0x0123456789AB0000 MOVK X3, 0xCDEF, LSL 00 // 0x0123456789ABCDEF

Condicionales y saltos

Mediante el uso de CBZ y CBNZ se puede hacer un salto condicional.
CBZ recibe un registro y una rama, y si el registro es 0 salta a la rama.
CBNZ recibe un registro y una rama, y si el registro es distinto de 0 salta a la rama.
B es un salto a una rama.

Ejemplo: bloque if en C:

if (i == j) { f = g + h; } else { f = g - h; }

Asignamos a las variables f, g, h, i, j los registros X0, X1, X2, X3, X4, respectivamente:

SUB X9, X3, X4 // i - j CBNZ X9, Else // i != j ⇒ salta a Else ADD X0, X1, X2 // f = g + h B Exit // salta a Exit Else: SUB X9, X1, X2 // f = g - h Exit: ...

Ejemplo: bloque while en C:

while (save[i] == k) { i += 1; }

Asignamos a las variables i, k los registros X0, X1, respectivamente. La dirección base del array save se almacena en el registro X2:

LSL X9, X0, #3 // i * 8 ADD X9, X9, X2 // &save[i] Loop: LDUR X10, [X9] // save[i] CBNZ X10, End // save[i] != k ⇒ salta a End ADDI X0, X0, #1 // i += 1 B Loop End: ...

Operaciones condicionales

Es posible modificar los valores de los flags N, Z, C, V mediante el uso de una instrucción con sufijo S (ADDS, ADDIS, SUBS, SUBIS, ANDS, ANDIS...)
Con la comparación, se puede hacer un salto condicional con B.EQ, B.NE, B.GE, B.LT, B.GT, B.LE...

Ejemplo: bloque if en C:

if (a > b) { a += 1; }

Asignamos a las variables a, b los registros X0, X1, respectivamente:

SUBS X9, X0, X1 // a - b B.GE Else // a <= b ⇒ salta a Else ADDI X0, X0, #1 // a += 1 Else: ...

También se puede usar CMP, CMPI para comparar sin almacenar el resultado en un registro:

CMP X0, X1 // comparar a, b B.GE Else // a <= b ⇒ salta a Else ADDI X0, X0, #1 // a += 1 Else: ...

Formato y ensamblado de instrucciones

Todas las instrucciones tienen un formato de \(32\) bits, donde la distribución de los bits depende del tipo de instrucción.

Instrucciones de tipo R

Las instrucciones de tipo R son aquellas que operan y reciben registros como argumentos.

  • opcode: la instrucción a ejecutar (por ejemplo, ADD, SUB, AND, ORR, etc.)
  • Rm: segundo registro operando.
  • shamt: desplazamiento (shift amount).
  • Rn: primer registro operando.
  • Rd: registro destino (donde se almacena el resultado de la operación).

OpcodeRmShamtRnRd
\(11\) bits\(5\) bits\(6\) bits\(5\) bits\(5\) bits

Instrucciones de tipo D

Las instrucciones de tipo D son aquellas que transfieren datos entre memoria y registros.


Opcodeaddressop2RnRt
\(11\) bits\(9\) bits\(2\) bits\(5\) bits\(5\) bits
  • address: offset de la dirección de memoria.

El valor de address debe ser el valor de la constante en base \(2\),
agregando los bits necesarios para llegar a \(9\) bits.

  • op2: expande el opcode (siempre debe estar seteado a 00).

Instrucciones de tipo I

Las instrucciones de tipo I son aquellas que operan con un valor inmediato.


OpcodeimmediateRnRd
\(10\) bits\(12\) bits\(5\) bits\(5\) bits
  • immediate: valor inmediato (constante). (de \(0\) a $2^12)

Instrucciones de tipo IM

Las instrucciones de tipo IM son aquellas que mueven contenidos entre registros.


OpcodeLSLMOV immediateRd
\(9\) bits\(2\) bits\(16\) bits\(5\) bits
  • LSL: desplazamiento a la izquierda (shift left). \(00 = 0, 01 = 16, 10 = 32, 11 = 48\)
  • MOV immediate: valor inmediato (constante). (de \(0\) a \(2^{16}\))

Instrucciones de tipo B

Las instrucción de tipo B (solo B) realiza saltos directos a otras instrucciones.


OpcodeBR address
\(6\) bits\(26\) bits

El valor de BR address es un binario cuyo valor es la cantidad de saltos realizados para llegar a la rama seleccionada (colocando los bits necesarios para llegar a \(26\))

Si se realizan tres saltos hacia adelante, su valor sería 00000000000000000000000011 = 3
Si se realizan tres saltos hacia atrás, su valor sería 11111111111111111111110011 = -3

Instrucciones de tipo CB

Las instrucciones de tipo CB son aquellas que realizan saltos condicionales a otras instrucciones.


OpcodeCOND BR addressRt
\(8\) bits\(19\) bits\(5\) bits

El criterio para poner el valor de COND BR address es el mismo que BR address, ajustando a \(19\) bits.

Última vez actualizado el 24 de mayo de 2025