Saltar al contenido

Cómo leer la notación Intel Opcode

Posterior a de una larga compilación de información hemos podido resolver este apuro que pueden tener algunos de nuestros usuarios. Te regalamos la solución y nuestro deseo es servirte de gran apoyo.

Solución:

3.1.1.1 Columna de código de operación en la tabla de resumen de instrucciones (instrucciones sin prefijo VEX)

La columna “Código de operación” en la tabla anterior muestra el código de objeto producido para cada forma de instrucción. Cuando es posible, los códigos se dan como bytes hexadecimales en el mismo orden en que aparecen en la memoria. Las definiciones de entradas distintas de los bytes hexadecimales son las siguientes:

• REX.W – Indica el uso de un prefijo REX que afecta el tamaño del operando o la semántica de la instrucción. El orden del prefijo REX y otros prefijos de instrucción opcionales / obligatorios se discuten en el Capítulo 2. Tenga en cuenta que los prefijos REX que promueven instrucciones heredadas al comportamiento de 64 bits no se enumeran explícitamente en la columna del código de operación.

• /dígito – Un dígito entre 0 y 7 indica que el byte ModR / M de la instrucción usa solo el operando r / m (registro o memoria). El campo reg contiene el dígito que proporciona una extensión al código de operación de la instrucción.

• / r – Indica que el byte ModR / M de la instrucción contiene un operando de registro y un operando r / m.

• cb, cw, cd, cp, co, ct – Un valor de 1 byte (cb), 2 bytes (cw), 4 bytes (cd), 6 bytes (cp), 8 bytes (co) o 10 bytes (ct) después del código de operación. Este valor se utiliza para especificar un desplazamiento de código y posiblemente un nuevo valor para el registro de segmento de código.

• ib, iw, id, io – Un operando inmediato de 1 byte (ib), 2 bytes (iw), 4 bytes (id) u 8 bytes (io) a la instrucción que sigue al código de operación, bytes ModR / M o bytes de indexación de escala. El código de operación determina si el operando es un valor con signo. Todas las palabras, palabras dobles y cuádruples se dan primero con el byte de orden inferior.

• + rb, + rw, + rd, + ro – Indica que los 3 bits inferiores del byte del código de operación se utilizan para codificar el operando del registro sin un byte modR / M. La instrucción enumera el valor hexadecimal correspondiente del byte del código de operación con 3 bits bajos como 000b. En el modo que no es de 64 bits, se agrega un código de registro, de 0 a 7, al valor hexadecimal del byte del código de operación. En el modo de 64 bits, indica el campo de cuatro bits de REX.by el código de operación[2:0] El campo codifica el operando de registro de la instrucción. “+ Ro” solo se aplica en el modo de 64 bits. Consulte la Tabla 3-1 para conocer los códigos.

• + i – Un número utilizado en instrucciones de punto flotante cuando uno de los operandos es ST (i) de la pila de registros FPU. El número i (que puede variar de 0 a 7) se agrega al byte hexadecimal dado a la izquierda del signo más para formar un solo byte de código de operación.

3.1.1.3 Columna de instrucción en la tabla de resumen del código de operación

La columna “Instrucción” proporciona la sintaxis de la declaración de instrucción como aparecería en un programa ASM386.

La siguiente es una lista de los símbolos utilizados para representar operandos en las instrucciones de instrucción:

• rel8 – Una dirección relativa en el rango de 128 bytes antes del final de la instrucción a 127 bytes después del final de la instrucción.

• rel16, rel32 – Una dirección relativa dentro del mismo segmento de código que la instrucción ensamblada. El símbolo rel16 se aplica a instrucciones con un atributo de tamaño de operando de 16 bits; el símbolo rel32 se aplica a instrucciones con un atributo de tamaño de operando de 32 bits.

• ptr16: 16, ptr16: 32 – Un puntero lejano, normalmente a un segmento de código diferente al de la instrucción. La notación 16:16 indica que el valor del puntero tiene dos partes. El valor a la izquierda de los dos puntos es un selector de 16 bits o un valor destinado al registro del segmento de código. El valor de la derecha corresponde al desplazamiento dentro del segmento de destino. El símbolo ptr16: 16 se utiliza cuando el atributo de tamaño de operando de la instrucción es de 16 bits; el símbolo ptr16: 32 se utiliza cuando el atributo de tamaño de operando es de 32 bits.

• r8 – Uno de los registros de uso general de bytes: AL, CL, DL, BL, AH, CH, DH, BH, BPL, SPL, DIL y SIL; o uno de los registros de bytes (R8L – R15L) disponibles cuando se usa REX.R y el modo de 64 bits.

• r16 – Uno de los registros de uso general de palabras: AX, CX, DX, BX, SP, BP, SI, DI; o uno de los registros de palabras (R8-R15) disponibles cuando se usa REX.R y el modo de 64 bits.

• r32 – Uno de los registros de uso general de dos palabras: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI; o uno de los registros de palabra doble (R8D – R15D) disponibles cuando se usa REX.R en modo de 64 bits.

• r64 – Uno de los registros de propósito general de cuatro palabras: RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP, R8 – R15. Están disponibles cuando se usa REX.R y el modo de 64 bits.

• imm8 – Un valor de byte inmediato. El símbolo imm8 es un número con signo entre –128 y +127 inclusive. Para las instrucciones en las que imm8 se combina con una palabra o un operando de dos palabras, el valor inmediato se extiende con el signo para formar una palabra o una palabra doble. El byte superior de la palabra se rellena con el bit superior del valor inmediato.

• imm16 – Un valor de palabra inmediata que se utiliza para instrucciones cuyo atributo de tamaño de operando es de 16 bits. Este es un número entre –32,768 y +32,767 inclusive.

• imm32 – Un valor de palabra doble inmediata que se utiliza para instrucciones cuyo atributo de tamaño de operando es de 32 bits. Permite el uso de un número entre +2,147,483,647 y –2,147,483,648 inclusive.

• imm64 – Valor inmediato de cuatro palabras que se utiliza para instrucciones cuyo atributo de tamaño de operando es de 64 bits. El valor permite el uso de un número entre +9,223,372,036,854,775,807 y –9,223,372,036,854,775,808 inclusive.

• r / m8 – Un operando de byte que es el contenido de un registro de propósito general de bytes (AL, CL, DL, BL, AH, CH, DH, BH, BPL, SPL, DIL y SIL) o un byte de la memoria. Los registros de bytes R8L – R15L están disponibles usando REX.R en modo de 64 bits.

• r / m16 – Un operando de memoria o registro de uso general de palabra utilizado para instrucciones cuyo atributo de tamaño de operando es de 16 bits. Los registros de uso general de palabras son: AX, CX, DX, BX, SP, BP, SI, DI. El contenido de la memoria se encuentra en la dirección proporcionada por el cálculo de la dirección efectiva. Los registros de palabras R8W – R15W están disponibles usando REX.R en modo de 64 bits.

• r / m32 – Un operando de memoria o registro de propósito general de dos palabras que se utiliza para instrucciones cuyo atributo de tamaño de operando es de 32 bits. Los registros de uso general de dos palabras son: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI. El contenido de la memoria se encuentra en la dirección proporcionada por el cálculo de la dirección efectiva. Los registros de doble palabra R8D – R15D están disponibles cuando se usa REX.R en modo de 64 bits.

• r / m64 – Un registro de propósito general de cuatro palabras o un operando de memoria que se usa para instrucciones cuyo atributo de tamaño de operando es de 64 bits cuando se usa REX.W. Los registros de propósito general de cuatro palabras son: RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP, R8 – R15; estos están disponibles solo en el modo de 64 bits. El contenido de la memoria se encuentra en la dirección proporcionada por el cálculo de la dirección efectiva.

• m – Un operando de 16, 32 o 64 bits en la memoria.

• m8 – Un operando de byte en la memoria, generalmente expresado como un nombre de variable o matriz, pero apuntado por los registros DS: (E) SI o ES: (E) DI. En el modo de 64 bits, lo señalan los registros RSI o RDI.

• m16 – Un operando de palabra en la memoria, generalmente expresado como un nombre de variable o matriz, pero apuntado por los registros DS: (E) SI o ES: (E) DI. Esta nomenclatura se usa solo con las instrucciones de cadena.

• m32 – Un operando de doble palabra en la memoria, generalmente expresado como un nombre de variable o matriz, pero apuntado por los registros DS: (E) SI o ES: (E) DI. Esta nomenclatura se usa solo con las instrucciones de cadena.

• m64 – Un operando de memoria de cuatro palabras en la memoria.

• m128 – Un operando de memoria de cuatro palabras dobles en la memoria.

• m16: 16, m16: 32 y m16: 64 – Un operando de memoria que contiene un puntero lejano compuesto por dos números. El número a la izquierda de los dos puntos corresponde al selector de segmento del puntero. El número de la derecha corresponde a su desplazamiento.

• m16 y 32, m16 y 16, m32 y 32, m16 y 64 – Un operando de memoria que consta de pares de elementos de datos cuyos tamaños se indican en el lado izquierdo y derecho del signo comercial. Se permiten todos los modos de direccionamiento de memoria. Los operandos m16 y 16 y m32 y 32 son utilizados por la instrucción BOUND para proporcionar un operando que contiene los límites superior e inferior para los índices de matriz. LIDT y LGDT utilizan el operando m16 & 32 para proporcionar una palabra con la que cargar el campo límite y una palabra doble con la que cargar el campo base de los registros GDTR e IDTR correspondientes. LIDT y LGDT utilizan el operando m16 y 64 en modo de 64 bits para proporcionar una palabra con la que cargar el campo límite y una palabra cuádruple con la que cargar el campo base de los registros GDTR e IDTR correspondientes.

• moffs8, moffs16, moffs32, moffs64 – Una variable de memoria simple (compensación de memoria) de tipo byte, palabra o palabra doble utilizada por algunas variantes de la instrucción MOV. La dirección real viene dada por un simple desplazamiento relativo a la base del segmento. No se utiliza ningún byte ModR / M en la instrucción. El número que se muestra con moffs indica su tamaño, que está determinado por el atributo de tamaño de dirección de la instrucción.

• Sreg – Un registro de segmento. Las asignaciones de bits de registro de segmento son ES = 0, CS = 1, SS = 2, DS = 3, FS = 4 y GS = 5.

• m32fp, m64fp, m80fp – Un operando de punto flotante de precisión simple, precisión doble y precisión extendida doble (respectivamente) en la memoria. Estos símbolos designan valores de punto flotante que se utilizan como operandos para instrucciones de punto flotante x87 FPU.

• m16int, m32int, m64int – Un operando entero de palabra, palabra doble y palabra cuádruple (respectivamente) en la memoria. Estos símbolos designan números enteros que se utilizan como operandos para instrucciones de números enteros x87 FPU.

• ST o ST (0) – El elemento superior de la pila de registros FPU.

• ST (i) – El i-ésimo elemento de la parte superior de la pila de registros FPU (i ← 0 a 7).

• mm – Un registro MMX. Los registros MMX de 64 bits son: MM0 a MM7.

• mm / m32 – Los 32 bits de orden inferior de un registro MMX o un operando de memoria de 32 bits. Los registros MMX de 64 bits son: MM0 a MM7. El contenido de la memoria se encuentra en la dirección proporcionada por el cálculo de la dirección efectiva.

• mm / m64 – Un MMX registro o un operando de memoria de 64 bits. Los registros MMX de 64 bits son: MM0 a MM7. El contenido de la memoria se encuentra en la dirección proporcionada por el cálculo de la dirección efectiva.

• xmm – Un registro XMM. Los registros XMM de 128 bits son: XMM0 a XMM7; XMM8 a XMM15 están disponibles usando REX.R en modo de 64 bits.

• xmm / m32— Un registro XMM o un operando de memoria de 32 bits. Los registros XMM de 128 bits son XMM0 a XMM7; XMM8 a XMM15 están disponibles usando REX.R en modo de 64 bits. El contenido de la memoria se encuentra en la dirección proporcionada por el cálculo de la dirección efectiva.

• xmm / m64 – Un registro XMM o un operando de memoria de 64 bits. Los registros de coma flotante SIMD de 128 bits son XMM0 a XMM7; XMM8 a XMM15 están disponibles usando REX.R en modo de 64 bits. El contenido de la memoria se encuentra en la dirección proporcionada por el cálculo de la dirección efectiva.

• xmm / m128 – Un registro XMM o un operando de memoria de 128 bits. Los registros XMM de 128 bits son XMM0 a XMM7; XMM8 a XMM15 están disponibles usando REX.R en modo de 64 bits. El contenido de la memoria se encuentra en la dirección proporcionada por el cálculo de la dirección efectiva.

• – Indica el uso implícito del registro XMM0. Cuando hay ambigüedad, xmm1 indica el primer operando fuente usando un registro XMM y xmm2 el segundo operando fuente usando un registro XMM. Algunas instrucciones usan el registro XMM0 como tercer operando fuente, indicado por. El uso del tercer operando del registro XMM está implícito en la codificación de la instrucción y no afecta la codificación ModR / M.

• mmm – Un registro YMM. Los registros YMM de 256 bits son: YMM0 a YMM7; YMM8 a YMM15 están disponibles en modo de 64 bits.

• m256 – Un operando de 32 bytes en la memoria. Esta nomenclatura se usa solo con instrucciones AVX.

• ymm / m256 – Un registro YMM o un operando de memoria de 256 bits.

• – Indica el uso del registro YMM0 como argumento implícito.

• bnd – Un registro de límites de 128 bits. BND0 a BND3.

• mib – Un operando de memoria que usa la forma de direccionamiento SIB, donde el registro de índice no se usa en el cálculo de la dirección, se ignora la escala. Solo la base y el desplazamiento se utilizan en el cálculo efectivo de direcciones.

• m512 – Un operando de 64 bytes en la memoria.

• zmm / m512 – Un registro ZMM o un operando de memoria de 512 bits.

• k1 z – Un registro de máscara utilizado como máscara de escritura de instrucciones. Los registros k de 64 bits son: k1 a k7. La especificación de la máscara de escritura está disponible exclusivamente a través del prefijo EVEX. El enmascaramiento se puede realizar como un enmascaramiento de fusión, donde los valores antiguos se conservan para los elementos enmascarados o como un enmascaramiento de puesta a cero. El tipo de enmascaramiento se determina mediante el bit EVEX.z.

• k1 – Sin z: un registro de máscara que se utiliza como máscara de escritura de instrucciones para las instrucciones que no permiten el enmascaramiento de cero pero admiten el enmascaramiento de fusión. Esto corresponde a instrucciones que requieren que el valor del campo aaa sea diferente de 0 (por ejemplo, recopilar) e instrucciones de tipo tienda que solo permiten fusionar-enmascarar.

• k1 – Un registro de máscara utilizado como operando regular (ya sea de destino o de origen). Los registros k de 64 bits son: k0 a k7.

• mV – Un operando de memoria vectorial; el tamaño del operando depende de la instrucción.

• vm32 x, y, z – Una matriz vectorial de operandos de memoria especificada mediante el direccionamiento de memoria VSIB. La matriz de direcciones de memoria se especifica utilizando un registro base común, un factor de escala constante y un registro de índice vectorial con elementos individuales de un valor de índice de 32 bits en un registro XMM (vm32x), un registro YMM (vm32y) o un registro ZMM (vm32z).

• vm64 x, y, z – Una matriz vectorial de operandos de memoria especificada mediante el direccionamiento de memoria VSIB. La matriz de direcciones de memoria se especifica mediante un registro base común, un factor de escala constante y un registro de índice vectorial con elementos individuales de un valor de índice de 64 bits en un registro XMM (vm64x), un registro YMM (vm64y) o un registro ZMM (vm64z).

• zmm / m512 / m32bcst – Un operando que puede ser un registro ZMM, una ubicación de memoria de 512 bits o un vector de 512 bits cargado desde una ubicación de memoria de 32 bits.

• zmm / m512 / m64bcst – Un operando que puede ser un registro ZMM, una ubicación de memoria de 512 bits o un vector de 512 bits cargado desde una ubicación de memoria de 64 bits.

• – Indica el uso del registro ZMM0 como argumento implícito.

• er – Indica soporte para control de redondeo integrado, que solo es aplicable a la forma de registro-registro de la instrucción. Esto también implica soporte para SAE (Suprimir todas las excepciones).

• sae – Indica soporte para SAE (Suprimir todas las excepciones). Se utiliza para instrucciones que admiten SAE, pero no admiten control de redondeo integrado.

• SRC1 – Denota el primer operando fuente en la sintaxis de instrucción de una instrucción codificada con el prefijo VEX / EVEX y que tiene dos o más operandos fuente.

• SRC2 – Denota el segundo operando fuente en la sintaxis de instrucción de una instrucción codificada con el prefijo VEX / EVEX y que tiene dos o más operandos fuente.

• SRC3 – Denota el tercer operando fuente en la sintaxis de instrucción de una instrucción codificada con el prefijo VEX / EVEX y que tiene tres operandos fuente.

• SRC – La fuente en una instrucción de fuente única.

• DST – el destino en una instrucción. Este campo está codificado por reg_field.

Mi fuente favorita es la propia Intel: Intel® 64 e IA-32 Architectures Software Developer Manuales. Y, a diferencia de las versiones anteriores, todos los volúmenes ahora están muy bien envueltos en un solo PDF (3044 páginas).

Parece que la sección que más le ayudará es 3.1.1.1 en el Capítulo 3 del Volumen 2 (página 432 del último PDF a la fecha en que escribo esto).

Muchos códigos de operación para versiones inmediatas de instrucciones, incluyendo 83, use el de 3 bits /r campo en el byte ModR / M como 3 bits de código de operación adicionales. El manual vol. 2 de Intel documenta esto, y creo que la tabla de códigos de operación en un apéndice lo incluye.

Esta es la razón por la que la mayoría de las instrucciones inmediatas originales-8086, como and r/m, imm todavía solo permite 2 operandos, a diferencia de shrd eax, edx, 4 o imul edx, [rdi], 12345 donde ambos campos ModRM se utilizan para codificar operandos dst / src, así como el código de operación que implica un operando inmediato.

SHRD / SHLD y se agregaron con 386, e imul-inmediato se agregó con 186. Es quizás desafortunado que copy-and-AND (and eax, edx, 0xf) no se puede codificar, pero al menos x86 puede usar LEA para operaciones muy comunes de copiar y agregar o suboperaciones.

Pero si cada instrucción inmediata y de un operando (como push o not) necesitaba un código de operación completo para sí mismo, 8086 se habría quedado sin códigos de operación de 1 byte. (Especialmente porque el diseñador decidió gastar mucho espacio de codificación en formularios cortos sin byte modrm para AL y AX, como cmp ax, 12345 siendo solo 3 bytes en lugar de 4 en el modo de 16 bits, o cmp eax, imm32 siendo solo 5 bytes en lugar de 6 para cmp r/m32, imm32 en modo de 32 bits. Y para el registro xchg-with-ax de un solo byte y un registro inc / dec de un byte).


Ejemplo: decodificación 48 83 C4 38. (desde ¿Cómo se decodifica un byte de código de operación a diferentes instrucciones dependiendo del campo “registro / código de operación”? ¿Qué es eso ?, un duplicado de esta Q)

48 es un prefijo REX.W (REX con solo el bit W establecido, por lo que indica el tamaño del operando de 64 bits, pero sin registros altos).

Código de operación 83 dice que pueden ser 7 instrucciones diferentes dependiendo de un campo llamado “campo de registro / código de operación”

Los documentos propios de cada instrucción, p. Ej. add (extracto html del manual vol2), muestra codificaciones como
REX.W + 83 /0 ib por ADD r/m64, imm8, que es lo que tienes.

diagrama de los campos de bits de ModRM de wiki.osdev.org

  7                           0
+---+---+---+---+---+---+---+---+
|  mod  |    reg    |     rm    |
+---+---+---+---+---+---+---+---+

0xc4 = 0b11000100, por lo que el campo reg = 0. Por lo tanto, nuestro código de operación es 83 /0, en la notación de Intel.

El resto de los campos de ModRM son:

  • mode = 0b11, por lo que el campo rm codifica un operando de registro, no un registro base para un modo de direccionamiento.
  • rm = 0b100. reg # 4 = SPL / SP / ESP / RSP. (En este caso RSP porque tiene un tamaño de operando de 64 bits). Consulte el manual de Intel o https://wiki.osdev.org/X86-64_Instruction_Encoding#Registers para obtener tablas.

Entonces la instrucción es add rsp, 0x38

ndisasm -b64 está de acuerdo:

$ cat > foo.asm
db 0x48, 0x83, 0xC4, 0x38
$ nasm foo.asm     # create a flat binary with those bytes, not an object file
$ ndisasm -b64 foo
00000000  4883C438          add rsp,byte +0x38

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *