Instrucciones de x86
En las listas de esta sección, las instrucciones marcadas con un asterisco (*) son especialmente importantes. Las instrucciones no tan marcadas no son críticas.
En el procesador x86, las instrucciones tienen un tamaño variable, por lo que el desensamblado hacia atrás es un ejercicio de coincidencia de patrones. Para desensamblar hacia atrás desde una dirección, debe empezar a desensamblar en un punto más allá de lo que realmente desea ir y, a continuación, mirar hacia adelante hasta que las instrucciones empiecen a tener sentido. Es posible que las primeras instrucciones no tengan sentido porque es posible que haya empezado a desensamblar en medio de una instrucción. Por desgracia, existe la posibilidad de que el desensamblado nunca se sincronice con el flujo de instrucciones y tendrá que intentar desensamblar en un punto de partida diferente hasta que encuentre un punto de partida que funcione.
En el caso de las instrucciones switch bien empaquetadas, el compilador emite datos directamente en el flujo de código, por lo que el desensamblado a través de una instrucción switch normalmente se encontrará en instrucciones que no tienen sentido (porque son realmente datos). Busque el final de los datos y continúe desensamblado allí.
Notación de instrucción
La notación general para obtener instrucciones es colocar el registro de destino a la izquierda y el origen a la derecha. Sin embargo, puede haber algunas excepciones a esta regla.
Las instrucciones aritméticas suelen ser dos registros con los registros de origen y destino que combinan. El resultado se almacena en el destino.
Algunas de las instrucciones tienen versiones de 16 y 32 bits, pero aquí solo se enumeran las versiones de 32 bits. No se enumeran aquí instrucciones de punto flotante, instrucciones con privilegios e instrucciones que se usan solo en modelos segmentados (que Microsoft Win32 no usa).
Para ahorrar espacio, muchas de las instrucciones se expresan en forma combinada, como se muestra en el ejemplo siguiente.
* |
MOV |
r1, r/m/#n |
r1 = r/m/#n |
significa que el primer parámetro debe ser un registro, pero el segundo puede ser un registro, una referencia de memoria o un valor inmediato.
Para ahorrar aún más espacio, las instrucciones también se pueden expresar como se muestra en lo siguiente.
* |
MOV |
r1/m, r/m/#n |
r1/m = r/m/#n |
lo que significa que el primer parámetro puede ser un registro o una referencia de memoria, y el segundo puede ser un registro, una referencia de memoria o un valor inmediato.
A menos que se indique lo contrario, cuando se usa esta abreviatura, no puede elegir la memoria para el origen y el destino.
Además, se puede anexar un sufijo de tamaño de bits (8, 16, 32) al origen o destino para indicar que el parámetro debe ser de ese tamaño. Por ejemplo, r8 significa un registro de 8 bits.
Memoria, transferencia de datos y conversión de datos
Las instrucciones de transferencia de memoria y datos no afectan a las marcas.
Dirección efectiva
* |
LEA |
r, m |
Carga de la dirección efectiva. (r = dirección de m) |
Por ejemplo, LEA eax, [esi+4] significa eax = esi + 4. Esta instrucción se usa a menudo para realizar aritméticas.
Transferencia de datos
MOV |
r1/m, r2/m/#n |
r1/m = r/m/#n |
|
MOVSX |
r1, r/m |
Mover con la extensión de signo. |
|
* |
MOVZX |
r1, r/m |
Mover con una extensión cero. |
MOVSX y MOVZX son versiones especiales de la instrucción mov que realizan la extensión de signo o ninguna extensión del origen al destino. Esta es la única instrucción que permite que el origen y el destino sean diferentes tamaños. (Y, de hecho, deben ser diferentes tamaños.
Manipulación de la pila
El registro esp apunta a la pila. El valor en esp es la parte superior de la pila (más recientemente insertado, primero que se va a extraer); Los elementos de pila más antiguos residen en direcciones superiores.
INSERTAR |
r/m/#n |
Insertar valor en la pila. |
|
POP |
r/m |
Valor pop de la pila. |
|
PUSHFD |
Inserte marcas en la pila. |
||
POPFD |
Pop flags from stack(Marcas emergentes de la pila). |
||
PUSHAD |
Inserte todos los registros enteros. |
||
POPAD |
Pop all integer registers. |
||
ENTRAR |
#n, #n |
Crear marco de pila. |
|
* |
SALIR |
Desmontar marco de pila |
El compilador de C/C++ no usa la instrucción enter . (La instrucción enter se usa para implementar procedimientos anidados en lenguajes como Algol o Pascal).
La instrucción leave es equivalente a:
mov esp, ebp
pop ebp
Conversión de datos
CBW |
Convertir byte (al) en palabras (ax). |
CWD |
Convierta word (ax) en dword (dx:ax). |
CWDE |
Convierta word (ax) en dword (eax). |
CDQ |
convierta dword (eax) en qword (edx:eax). |
Todas las conversiones realizan la extensión de signo.
Manipulación aritmética y bit
Todas las instrucciones de manipulación aritmética y bit modifican marcas.
Aritmética
ADD |
r1/m, r2/m/#n |
r1/m += r2/m/#n |
|
ADC |
r1/m, r2/m/#n |
r1/m += r2/m/#n + transporte |
|
SUB |
r1/m, r2/m/#n |
r1/m -= r2/m/#n |
|
SBB |
r1/m, r2/m/#n |
r1/m -= r2/m/#n + transporte |
|
NEG |
r1/m |
r1/m = -r1/m |
|
INC |
r/m |
r/m += 1 |
|
DEC |
r/m |
r/m -= 1 |
|
CMP |
r1/m, r2/m/#n |
Proceso r1/m: r2/m/#n |
La instrucción cmp calcula la resta y establece marcas según el resultado, pero produce el resultado. Normalmente va seguido de una instrucción de salto condicional que prueba el resultado de la resta.
MUL |
r/m8 |
Ax = al * r/m8 |
|
MUL |
r/m16 |
dx:ax ax = * r/m16 |
|
MUL |
r/m32 |
edx:eax eax = * r/m32 |
|
IMUL |
r/m8 |
Ax = al * r/m8 |
|
IMUL |
r/m16 |
dx:ax ax = * r/m16 |
|
IMUL |
r/m32 |
edx:eax eax = * r/m32 |
|
IMUL |
r1, r2/m |
r1 *= r2/m |
|
IMUL |
r1, r2/m, #n |
r1 = r2/m * #n |
Multiplicación sin signo y firmada. El estado de las marcas después de la multiplicación no está definido.
DIV |
r/m8 |
(ah, al) = (ax % r/m8, ax / r/m8) |
|
DIV |
r/m16 |
(dx, ax) = dx:ax / r/m16 |
|
DIV |
r/m32 |
(edx, eax) = edx:eax / r/m32 |
|
IDIV |
r/m8 |
(ah, al) = ax / r/m8 |
|
IDIV |
r/m16 |
(dx, ax) = dx:ax / r/m16 |
|
IDIV |
r/m32 |
(edx, eax) = edx:eax / r/m32 |
División sin firmar y firmada. El primer registro de la explicación de pseudocódigo recibe el resto y el segundo recibe el cociente. Si el resultado desborda el destino, se genera una excepción de desbordamiento de división.
El estado de las marcas después de la división no está definido.
* |
SETcc |
r/m8 |
Establecer r/m8 en 0 o 1 |
Si la condición cc es true, el valor de 8 bits se establece en 1. De lo contrario, el valor de 8 bits se establece en cero.
Decimal codificado binario
No verá estas instrucciones a menos que esté depurando código escrito en COBOL.
DAA |
Ajuste decimal después de la adición. |
|
DAS |
Ajuste decimal después de la resta. |
Estas instrucciones ajustan el registro al después de realizar una operación decimal codificada binaria empaquetada.
AAA |
ASCII se ajusta después de la adición. |
AAS |
Ajuste ASCII después de la resta. |
Estas instrucciones ajustan el registro al después de realizar una operación decimal codificada binaria desempaquetada.
AAM |
ASCII se ajusta después de la multiplicación. |
AAD |
Ajuste ASCII después de la división. |
Estas instrucciones ajustan los registros al y ah después de realizar una operación decimal codificada binaria desempaquetada.
Bits
AND |
r1/m, r2/m/#n |
r1/m = r1/m y r2/m/#n |
|
O BIEN |
r1/m, r2/m/#n |
r1/m = r1/m o r2/m/#n |
|
XOR |
r1/m, r2/m/#n |
r1/m = r1/m xor r2/m/#n |
|
NOT |
r1/m |
r1/m = bit a bit not r1/m |
|
* |
PRUEBA |
r1/m, r2/m/#n |
Proceso r1/m y r2/m/#n |
La instrucción de prueba calcula el operador AND lógico y establece marcas según el resultado, pero elimina el resultado. Normalmente va seguida de una instrucción de salto condicional que prueba el resultado del AND lógico.
SHL |
r1/m, cl/#n |
r1/m <<= cl/#n |
|
SHR |
r1/m, cl/#n |
r1/m >>= cl/#n relleno cero |
|
* |
SAR |
r1/m, cl/#n |
r1/m >>= cl/#n sign-fill |
El último bit desplazado se coloca en la carga.
SHLD |
r1, r2/m, cl/#n |
Mayús doble a la izquierda. |
Mayús r1 a la izquierda por cl/#n, rellenando con los bits superiores de r2/m. El último bit desplazado se coloca en la carga.
SHRD |
r1, r2/m, cl/#n |
Desplazá a la derecha doble. |
Mayús r1 a la derecha por cl/#n, rellenando con los bits inferiores de r2/m. El último bit desplazado se coloca en la carga.
ROL |
r1, cl/#n |
Gire r1 a la izquierda por cl/#n. |
ROR |
r1, cl/#n |
Gire r1 a la derecha por cl/#n. |
RCL |
r1, cl/#n |
Gire r1/C a la izquierda por cl/#n. |
RCR |
r1, cl/#n |
Gire r1/C a la derecha por cl/#n. |
La rotación es como cambiar, excepto que los bits que se desplazan se vuelven a aparecer como los bits de relleno entrantes. La versión del lenguaje C de las instrucciones de rotación incorpora el bit de transporte a la rotación.
BT |
r1, r2/#n |
Copie el bit r2/#n de r1 en transporte. |
BTS |
r1, r2/#n |
Establezca bit r2/#n de r1, copie el valor anterior en carry. |
BTC |
r1, r2/#n |
Borre el bit r2/#n de r1 y copie el valor anterior en la carga. |
Flujo de control
Jcc |
Dest |
Condicional de rama. |
|
JMP |
Dest |
Salta directamente. |
|
JMP |
r/m |
Saltar indirecto. |
|
CALL |
Dest |
Llame directo. |
|
* |
CALL |
r/m |
Llame a indirecto. |
La instrucción de llamada inserta la dirección de retorno en la pila y, a continuación, salta al destino.
* |
RET |
#n |
Valor devuelto |
La instrucción ret aparece y salta a la dirección de retorno de la pila. Un #n distinto de cero en la instrucción RET indica que después de extraer la dirección de retorno, el valor #n debe agregarse al puntero de pila.
BUCLE |
Disminuir ecx y saltar si result es distinto de cero. |
LOOPZ |
Disminuir ecx y saltar si result es distinto de cero y zr se estableció. |
LOOPNZ |
Disminuir ecx y saltar si el resultado es distinto de cero y zr estaba claro. |
JECXZ |
Saltar si ecx es cero. |
Estas instrucciones son restos del patrimonio CISC de x86 y en procesadores recientes son realmente más lentos que las instrucciones equivalentes escritas durante mucho tiempo.
Manipulación de cadenas
MOVST |
Mover T de esi a edi. |
|
CMPS T |
Compare T de esi con edi. |
|
SCAS T |
Escanear T desde edi para accT. |
|
LODST |
Cargue T de esi enacc T. |
|
STOST |
Almacenar T a edi desdeacc T. |
Después de realizar la operación, el registro de origen y destino se incrementa o disminuye según sizeof(T), según el valor de la marca de dirección (arriba o abajo).
Rep puede prefijar la instrucción para repetir la operación el número de veces especificado por el registro ecx .
La instrucción rep mov se usa para copiar bloques de memoria.
La instrucción rep stos se usa para rellenar un bloque de memoria con accT.
Banderas
LAHF |
Cargue ah desde marcas. |
SAHF |
Almacenar ah en marcas. |
STC |
Defina la carga. |
CLC |
Transporte claro. |
CMC |
Transporte complementario. |
STD |
Establezca la dirección en abajo. |
CLD |
Establezca la dirección hacia arriba. |
STI |
Habilite las interrupciones. |
CLI |
Deshabilite las interrupciones. |
Instrucciones interbloqueadas
XCHG |
r1, r/m |
Intercambiar r1 y r/m. |
XADD |
r1, r/m |
Agregue r1 a r/m, coloque el valor original en r1. |
CMPXCHG |
r1, r/m |
Compare e intercambie condicional. |
La instrucción cmpxchg es la versión atómica de lo siguiente:
cmp accT, r/m
jz match
mov accT, r/m
jmp done
match:
mov r/m, r1
done:
Misceláneos
INT |
#n |
Interceptar al kernel. |
|
LÍMITE |
r, m |
Interceptar si r no está dentro del intervalo. |
|
* |
NOP |
No hay ninguna operación. |
|
XLATB |
al = [ebx + al] |
||
BSWAP |
r |
Intercambiar el orden de bytes en el registro. |
Este es un caso especial de la instrucción int .
INT |
3 |
Captura de punto de interrupción del depurador. |
El código de operación de INT 3 es 0xCC. El código de operación para NOP es 0x90.
Al depurar código, es posible que tenga que aplicar revisiones a algún código. Para ello, reemplace los bytes infractores por 0x90.
Idiomas
XOR |
r, r |
r = 0 |
|
PRUEBA |
r, r |
Compruebe si r = 0. |
|
* |
ADD |
r, r |
Mayús r a la izquierda por 1. |