Bem,
há um tempo atráz fiquei imaginando como uma instrução em assembly é transformada em uma instrução em hex. Depois de algumas pesquisas percebi que todas as intruções, opCodes, tem um número. Depois da tabela dos opCodes veio outra dúvida como é passado os parâmetros em uma instrução Mov Al, 0x20, como sabem os parâmetros e valores que será passado para a instrução. E para instruções do tipo Mov [Edx], Cl, ou então para
Add [Ecx+Ebx*4+439BCE28], Cl, ai que a coisa começa ficar elegante. E é justamente isso que será visto nesse tutorial.
Abaixo está a tabela onde verificamos qual é o valor em hex de uma instrução.
Bem para encontrar como por exemplo o que qual é a instrução do número 0x46 o primeiro dígito(high digit) quer dizer a linha e o segundo digito(low digit) a coluna, que seria a instrução INC SI.
Por exemplo a instrução NOP é 90.
O high digit é o 9 e o low digit é o 0.
A instrução Inc Di o seu valor é 47.
O high digit é o 4 e o low digit é o 7.
Agora para saber mais sobre as intruções aqui você encontra mais informações.
Add [Ecx+Ebx*4+439BCE28], Cl, ai que a coisa começa ficar elegante. E é justamente isso que será visto nesse tutorial.
Abaixo está a tabela onde verificamos qual é o valor em hex de uma instrução.
Bem para encontrar como por exemplo o que qual é a instrução do número 0x46 o primeiro dígito(high digit) quer dizer a linha e o segundo digito(low digit) a coluna, que seria a instrução INC SI.
Por exemplo a instrução NOP é 90.
O high digit é o 9 e o low digit é o 0.
A instrução Inc Di o seu valor é 47.
O high digit é o 4 e o low digit é o 7.
Agora para saber mais sobre as intruções aqui você encontra mais informações.
b = Byte-Operand w = Word-Operand f = from CPU-Register t = to CPU-Register m = memory r/m = Register/Memory sr = Segmentregister d = direct si = short intrasegment i = immediate ia = immediate accu d = direct addressing id = indirect addressing is = immediate byte sign-extended v = variable (IO-addr, in DX or shift-count in CL) d8 = direkte 8-Bit-Adresse(I/O) nr = near(16 - 64K) fr = far (32 bit - 1M) |
Bem vamos começar a analizar do começo :P
Usando um exemplo simples, usando uma instrução Mov.
Um exemplo de colocar um valor 30 para o registrador EAX.
Utilizando o opCode 88, de acordo com a tabela temos os seguintes valores.
Usando um exemplo simples, usando uma instrução Mov.
Ele movimenta dados de uma origem para um destino.
Mov destino, origem |
Mov EAX, 30 |
88 - MOV (b, f, r/m) |
Bem o valor 88 é um byte (b) o valor tá vindo do CPU (f) e é do registrador para memória (r/m).
Vamos analizar a instrução abaixo:
88 0a - Mov [Edx], Cl |
Como é apenas um bye temos como "parâmetro" o byte 0a. O nome desse byte é ModR/M. Esse "parâmetro" é que define para quem que vai e de onde vai(Destino e Origem).
Convertendo o 0a para binário temos 00001010, o binário é divido em 3 grupos 00 001 010.
00 - Byte Mod 001 - Reg/Opcode 010 - R/M |
Para esse tipo de instrução 001 é a fonte o destino é 010. A tabela abaixo mostra os valores de cada registrador em binário.
Register Byte | Register Word | Register DWord |
AL = 000 CL = 001 DL = 010 BL = 011 AH = 100 CH = 101 DH = 110 BH = 111 | AX = 000 CX = 001 DX = 010 BX = 011 SP = 100 BP = 101 SI = 110 DI = 111 | EAX = 000 ECX = 001 EDX = 010 EBX = 011 ESP = 100 EBP = 101 ESI = 110 EDI = 111 |
Como o primeiro operador é b quer dizer byte ou seja 8 bits, por isso usamos o registrador de origem de 8 byte. E o opCode nos diz que está vindo do CPU (f - From CPU) para a memória(R/M - Register/Memory).
Analizando a tabela obtemos os seguintes valores.
Então analizando os opCode's 88 0a quer dizer a seguinte instrução em assembly.
Analizando a tabela obtemos os seguintes valores.
001 - Registrador Cl (8 bytes) |
010 - Edx como é r/m [Edx] |
Mov [Edx], Cl |
Bem mais um exemplo simples.
89 03 - Mov [Ebx], Ax |
89 - Mov (w, f, r/m) |
Bem o valor 89 vamos mexer com word(w) o valor tá vindo do CPU (f) e é do registrador para memória (r/m).
Transformando o 03 para binário temos 00 000 100 resultando na instrução.
000 - registrador origem (Ax) |
100 - registrador fonte (Bx) |
Como é r/m é do registrador para memória temos.
Mov [bx], ax |
b0 (i -> Al) |
b0 6e - Mov Al, 6e |
Agora o opCode B8 trabalha com 32 bits.
b8 63 bc 38 4e - Mov Eax, 4e38bc63 |
Bytes da intrução:
63 bc 38 4e <------------: |
Mov Eax, 4e38bc63 |
Vamos falar agora de alguns instruções um pouco diferentes como:
00 a8 8a 6e e1 58 - Add [eax+58e16e8a], Ch |
Add (b, f, r/m) |
a8 em binário é igual a 10101000 então:
10 - Byte Mod 101 - Registrador Origem (Ch) 000 - R/M |
Bem agora vimos que o byte Mod é 10.
Abaixo uma tabela de do byte Mod para podermos encontrar os valores.
Dependendo do tamanho da instrução 16 ou 32 bit.
Para o mod igual á 10 e R/M igual á 000 temos:
[bx+si]+disp16 |
58 e1 6e 8a |
Agora vem a pergunta onde encontramos o Eax bem juntando o mod + R/M temos
10 000 000 transformando para hexadecimal temos 0x80 que é a coluna do registrador Eax.
Juntando tudo tempos.
Add [Eax+58e16e8a], Ch |
Temos também instruções de salto como:
00280721 - ea 66 bc 38 4e 23 e2 - jmp e223:4e38bc66
De acordo com a tabela o opCode ea.
Jmp (fr, d) |
O pula vai ser longo(fr) e o endereço vai ser direto(d).
Bem aqui pegamos os 16 bytes iniciais ou seja e223 é o seguimento e o restante é offset.
e223:4e38bc66 |
Bem a idéia principal foi passada, ainda tem algumas intruções para serem analizadas, mas o básicão é isso.
Agora alguns links uteis.
http://pdos.csail.mit.edu/6.828/2007/readings/i386/c17.htm
http://labts101.zhaw.ch/~tham/TIn1/unterlagen/opcodes.pdf
http://www.intel.com/products/processor/manuals/
http://pdos.csail.mit.edu/6.828/2006/readings/i386/s17_02.htm
Valeuw.
2 comentários:
Grande Danilão!! Apavorando com mais um otimos post!!
[s]
by
6_Bl4ck9_f0x6
oww !
Muito bom, a pergunta: como funciona? também me incomoda muito. Hehhe
Parábens.
Postar um comentário