instruction asm assembly x86 gnu opcode protected-mode

assembly - asm - ¿Alguien puede explicar este código de operación J86 x86 ensamblado directamente?



opcode to asm (3)

En la escuela, hemos estado usando un programa de arranque para ejecutar programas independientes sin un sistema operativo. He estado estudiando este programa y cuando está habilitado el modo protegido, se ejecuta un salto lejano ensamblando directamente el código de operación y los operandos como datos dentro del programa. Esto fue para el ensamblador GNU:

/* this code immediately follows the setting of the PE flag in CR0 */

.byte 0x66, 0xEA .long TARGET_ADDRESS .word 0x0010 /* descriptor #2, GDT, RPL=0 */

Antes que nada, ¿por qué querría uno hacer esto (en lugar de la instrucción mnemotécnica)?

He estado mirando los manuales de Intel, pero todavía estoy un poco confundido por el código. Específicamente en el Volumen 2A, página 3-549, hay una tabla de códigos de operación. La entrada relevante:

EA *cp* JMP ptr16:32 Inv. Valid Jump far, absolute, address given in operand

El código de operación real es obvio, pero el primer byte, 0x66, me tiene confundido. En referencia a la tabla en el manual de Intel, el cp aparentemente significa que seguirá un operando de 6 bytes. Y obviamente 6 bytes siguen en las siguientes dos líneas. 0x66 codifica un ''Prefijo de anulación de tamaño de operando''. ¿Qué tiene esto que ver con el CP en la tabla? Esperaba que hubiera algún valor hexadecimal para el CP, pero en su lugar existe este prefijo de anulación. ¿Puede alguien aclarar esto por mí?

Aquí hay un volcado de od:

c022 **ea66 0000 0001 0010** ba52 03f2 c030

TARGET_ADDRESS se definió como 0x00010000.

También estoy un poco confundido por la importancia de los dos últimos bytes. Sin embargo, esa parece ser otra pregunta por completo. Se está haciendo bastante tarde, y he estado mirando el código y los manuales de Intel durante horas, así que espero haber aclarado mi punto.

¡Gracias por mirar!


0x66 especifica la anulación del tamaño del operando del tamaño del segmento del código actual. Suponiendo que el tamaño del código actual es de 16 bits, el nuevo puntero de instrucción será de 32 bits, no de 16 bits. Si el tamaño del segmento de código actual es de 32 bits, el 0x66 convertirá el puntero de instrucción de destino en 16 bits. El atributo de tamaño de código actual depende del selector CS en uso y sus atributos cargados desde la tabla GDT / LDT. En modo real, el tamaño del segmento de código suele ser de 16 bits, excepto en los casos especiales del modo "irreal".


El 0x66 indica que el JMP (0xEA) se refiere a seis bytes. El valor predeterminado se refiere a 64K (16 bits) en modo real o a 32 bits en modo protegido (si recuerdo bien). Al aumentarlo, también incluye el descriptor de segmento, el índice del segmento en el GDT o el LDT, lo que significa que este código está haciendo lo que tradicionalmente se llama un "salto de longitud": un salto que cruza más allá de los segmentos en el arquitectura x86. El segmento, en este caso, apunta a la segunda entrada en el GDT. Si mira antes en ese programa, probablemente verá cómo se define el GDT en términos de la dirección y longitud de inicio del segmento (consulte el manual de Intel para estudiar las tablas GDT y LDT, entrada de 32 bits que describe cada segmento).


Me encuentro con esto un poco. Algunos ensambladores solo saltarán a una ETIQUETA. En este caso, la persona quiere hacer un salto absoluto a un desplazamiento codificado duro específico. jmp TARGET_ADDRESS no funcionará. Estoy adivinando, por lo que solo lo ponen como bytes para evitar este problema.