Uso básico de inmediatos frente a corchetes en el ensamblaje YASM/NASM x86
Supongamos que tengo lo siguiente declarado:
section .bss
buffer resb 1
Y estas instrucciones siguen en section .text
:
mov al, 5 ; mov-immediate
mov [buffer], al ; store
mov bl, [buffer] ; load
mov cl, buffer ; mov-immediate?
¿Estoy en lo cierto al entender que bl contendrá el valor 5 y cl contendrá la dirección de memoria de la variable?buffer
?
Estoy confundido acerca de las diferencias entre
- mover un inmediato a un registro,
- mover un registro a un inmediato (¿qué entra, los datos o la dirección?) y
- mover un inmediato a un registro sin los corchetes
- Por ejemplo,
mov cl, buffer
frente amov cl, [buffer]
- Por ejemplo,
ACTUALIZACIÓN: Después de leer las respuestas, supongo que el siguiente resumen es exacto:
mov edi, array
coloca la dirección de memoria del índice de matriz cero enedi
. es decir, la dirección de la etiqueta.mov byte [edi], 3
pone el VALOR 3 en el índice cero de la matriz- después
add edi, 3
,edi
ahora contiene la dirección de memoria del tercer índice de la matriz mov al, [array]
carga los DATOS en el índice cero enal
.mov al, [array+3]
carga los DATOS en el tercer índice enal
.mov [al], [array]
no es válido porque x86 no puede codificar 2 operandos de memoria explícitos y porqueal
solo tiene 8 bits y no se puede usar ni siquiera en un modo de direccionamiento de 16 bits. Hacer referencia al contenido de una ubicación de memoria. (modos de direccionamiento x86)mov array, 3
no es válido porque no puedes decir "Oye, no me gusta el desplazamiento en el quearray
está almacenado, así que lo llamaré 3". Un inmediato sólo puede ser un operando fuente.mov byte [array], 3
coloca el valor 3 en el índice cero (primer byte) de la matriz. Elbyte
especificador es necesario para evitar ambigüedad entre byte/palabra/dword para instrucciones con memoria y operandos inmediatos. De lo contrario, sería un error en tiempo de ensamblaje (tamaño de operando ambiguo).
Por favor mencione si alguno de estos es falso. (nota del editor: arreglé errores/ambigüedades de sintaxis para que los válidos sean en realidad sintaxis NASM válida. Y vinculé otras preguntas y respuestas para obtener más detalles)
Los corchetes funcionan esencialmente como un operador de desreferencia (por ejemplo, como *
en C).
Entonces, algo como
mov REG, x
mueve el valor de x
hacia REG
, mientras que
mov REG, [x]
mueve el valor de la ubicación de memoria a la que x
apunta hacia REG
. Tenga en cuenta que si x
es una etiqueta, su valor es la dirección de esa etiqueta.
En cuanto a tu pregunta:
¿Estoy en lo cierto al entender que bl contendrá el valor 5 y cl contendrá la dirección de memoria del búfer variable?
Sí, estás en lo correcto. Pero ojo que, al CL
tener sólo 8 bits de ancho, sólo contendrá el byte menos significativo de la dirección del buffer
.
De hecho, su pensamiento es correcto. Es decir, bl contendrá 5 y cl la dirección de memoria del búfer (de hecho, el búfer de etiquetas es una dirección de memoria en sí).
Ahora, déjame explicarte las diferencias entre las operaciones que mencionaste:
Se puede mover un elemento inmediato a un registro usando
mov reg,imm
. Lo que puede resultar confuso es que las etiquetas, por ejemplo, el búfer, son valores inmediatos que contienen una dirección.Realmente no puedes mover un registro a un inmediato, ya que los valores inmediatos son constantes, como
2
oFF1Ah
. Lo que puedes hacer es mover un registro al lugar donde apunta la constante. Puedes hacerlo comomov [const], reg
.También puede utilizar el direccionamiento indirecto, como
mov reg2,[reg1]
los puntos reg1 proporcionados a una ubicación válida, y transferirá el valor señalado por reg1 a reg2.
Por lo tanto, mov cl, buffer
moverá la dirección del búfer a cl (que puede dar o no la dirección correcta, ya que cl tiene solo un byte de longitud), mientras que mov cl, [buffer]
obtendrá el valor real.
Resumen
- Cuando usas [a], entonces te refieres al valor en el lugar al que apunta a. Por ejemplo, si a es
F5B1
, entonces [a] se refiere a la dirección F5B1 en la RAM . - Las etiquetas son direcciones, es decir, valores como
F5B1
. - No es necesario hacer referencia a los valores almacenados en registros como [reg] porque los registros no tienen direcciones. De hecho, los registros pueden considerarse como valores inmediatos.
Estás entendiendo la idea. Sin embargo, hay algunos detalles que vale la pena tener en cuenta:
- Las direcciones pueden, y generalmente son, mayores de lo que pueden contener 8 bits (
cl
son 8 bits,cx
son 16 bits,ecx
son 32 bits,rcx
son 64 bits). Por lo tanto,cl
es probable que no sea igual a la dirección de la variablebuffer
. Sólo tendrá los 8 bits menos significativos de la dirección. - Si hay rutinas de interrupción o subprocesos que pueden adelantarse al código y/o acceso anterior
buffer
, el valor enbl
puede diferir de 5. Las rutinas de interrupción rotas pueden afectar a cualquier registro cuando no preservan los valores de los registros.
Para todas las instrucciones que utilizan valores inmediatos como operandos para escribir el valor en una ubicación de RAM (o para calcular dentro), tenemos que especificar a cuántos bytes queremos acceder. Porque nuestro ensamblado no puede saber si queremos acceder solo a un byte , una palabra o una doble palabra , por ejemplo si el valor inmediato es un valor menor, como lo muestran las siguientes instrucciones.
array db 0FFh, 0FFh, 0FFh, 0FFh
mov byte [array], 3
resultados:
array db 03h, 0FFh, 0FFh, 0FFh
....
mov word [array], 3
resultados:
array db 03h, 00h, 0FFh, 0FFh
....
mov dword [array], 3
resultados:
array db 03h, 00h, 00h, 00h
Puñal