Alguém pode explicar isso diretamente montados opcode x86 JMP?
-
23-08-2019 - |
Pergunta
Na escola temos vindo a utilizar um programa de inicialização para executar programas stand-alone sem um sistema operacional. Eu tenho estudado este programa e quando o modo protegido está habilitado há um salto muito executado por montar diretamente o opcode e operandos como dados dentro do programa. Este foi para a montador 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 */
Em primeiro lugar, porque é que um quer fazer isso (em vez do mnemônico de instrução)?
Eu tenho estado a olhar para os manuais Intel, mas ainda estou um pouco confuso com o código. Especificamente em 2A Volume, página 3-549, há uma mesa de opcodes. A entrada relevante:
EA *cp* JMP ptr16:32 Inv. Valid Jump far, absolute, address given in operand
O código de operação real é óbvio, mas o primeiro byte, 0x66, tem me confundiu. Referindo-se à tabela no manual da Intel, o CP, aparentemente, significa que um byte 6 operando seguirá. E, obviamente, 6 bytes seguir nas próximas duas linhas. 0x66 codifica um 'Operando de tamanho substituição prefixo'. O que isso tem a ver com a cp na tabela? Eu estava esperando que haja algum valor hexadecimal para o cp, mas em vez disso, há esse prefixo override. Alguém por favor pode esclarecer isso para mim?
Aqui é um lixo a partir od:
c022 **ea66 0000 0001 0010** ba52 03f2 c030
TARGET_ADDRESS foi definida como 0x00010000.
Eu também estou confuso um pouco pelo significado dos dois últimos bytes. No entanto, isso parece ser uma outra questão completamente. Está ficando muito tarde, e eu tenho estado a olhar para o código e os manuais Intel para horas, então eu espero que eu tenho o meu ponto de vista.
Agradecimentos para olhar!
Solução
O 0x66 indica que o JMP (0xEA) refere-se a seis bytes. O padrão é referindo-se a 64K (16 bits) em modo real ou a 32 bits em modo protegido (se me lembro bem). Tê-lo aumentado, também inclui o descritor de segmento, o índice do segmento tanto no GDT ou o LDT, o que significa que este código está fazendo o que é tradicionalmente chamado de "salto em distância": um salto que os segmentos além cruzadas no arquitetura x86. O segmento, neste caso, aponta para a segunda entrada na GDT. Se você olhar antes nesse programa, é provável que você ver como o GDT é definido em termos do segmento de endereço inicial e comprimento (olhar no manual Intel para estudar as tabelas GDT e LDT, 32 entrada bit descrevendo cada segmento).
Outras dicas
eu me deparo com isso um pouco. Algumas montadoras só vai saltar para um rótulo. Neste caso, a pessoa quer fazer um salto absoluto para um específico codificado offset. jmp TARGET_ADDRESS não vai funcionar Eu estou supondo, então eles simplesmente colocá-lo como bytes de contornar este problema.
0x66 especifica operando override tamanho do tamanho atual segmento de código. Assumindo que o tamanho do código atual é de 16 bits, o novo ponteiro de instrução será de 32 bits, não de 16 bits. Se o tamanho actual segmento de código é de 32 bits, a 0x66 irá processar ponteiro instrução de destino como de 16 bits. A corrente de atributo de tamanho de código depende selector de CS no uso e os seus atributos carregado a partir GDT mesa / LDT. Em modo real o tamanho do segmento de código é geralmente de 16 bits, exceto casos especiais de modo "irreal".