comp coop 10

24/09/2009

Interrupção do x86, Minix e, de quebra, uma pitada de estouro de pilha

RussoVaderpor Eduardo Russo

Um dos trabalhos que tivemos (eu, o João Misko e o Rafael Medeiros) que fazer para a disciplina de Sistemas Operacionais foi sobre estouro de pilhas no Minix. Como e onde ocorria, e como era tratado.

O grande salto quântico disso, era entender a tabela de interrupções do x86. Onde fica, para onde aponta e o que faz. Salto dado graças à imensa ajuda do Mestre Jorge Sabaliauskas! Se você não conhece o Jorjão, sinto muito!

Tabela de interrupção

Todo processador moderno possui uma tabela de interrupção (chamada de IDT – Interrupt Description Table – a partir daqui), que tem a função principal de executar uma determinada rotina (definida pelo SO) quando ocorre uma interrupção de hardware.

No x86, a tabela de interrupções é descrita conforme a tabela abaixo:

Exceções e interrupções

Tabela de exceções e interrupções retirada do manual "IA32-System-Programming-3A.pdf", Vol 3 5-3, para ser mais exato

Para entender um pouco melhor o que isso faz, usaremos o exemplo clássico da divisão por zero (não, não pode dividir por zero).

Sempre que algum programador tosco (como eu) solicitar uma divisão por zero (não pode mesmo!), o processador dá um berro e passa aponta o PC (Program Counter – o cara que aponta para o próximo trecho da memória a ser executado) para o endereço armazenado na posição zero da IDT.

A partir daí, o SO passa a tratar isso, inserindo o código de como quer tratar esse erro na posição apontada pela IDT.

Use Bochs, die alone

Antes de tudo, para conseguir encontrar o código apontado pela tabela de interrupção, você precisa usar o Bochs e com a versão de debug. Por que? Porque ele é um emulador e não um virtualizador. Dessa forma, você consegue ver as chamadas feitas ao hardware e manipular coisas que você não conseguiria manipular num virtualizador ou num computador real.

Direto da Wikipedia: “Num emulador, todos os recursos do sistema são processados nele (SIC) ao contrário da virtualização (SIC) que é uma ponte entre o hardware nativo e as chamadas do sistema operacional.”

Recomendo o Bochs de Windows, já que ele já vem compilado em sua última versão. Testei tanto pra OS X através do DarwinPorts, como pro Linux, mas a versão de Windows foi a que rodou mais tranquila. No Mac, o progrma rodava extremamente lento, no Linux, tive diversos problemas durante a compilação para conseguir ativar o debuger. No Windows, foi só clicar duas vezes.

Achando a IDT e vendo a interrupção

Até então, vimos a parte teórica, relativamente fácil de entender… Conseguir achar isso na prática requer um pouco mais de paciência e ajuda do Jorjão (ou de um blog como esse, se você não conhece o Jorjão).

Para proteger o código apontado pela IDT, o x86 usa algumas artimanhas. Em vez de simplesmente apontar para o endereço da memória, ele utiliza uma base e um offset.

Para explicar melhor isso, vou usar o exemplo do trabalho sobre estouro de pilhas que fiz, e mostrar na prática o endereço usado pelo x86. Você pode ver na tabela acima que Stack-Segment Fault encontra-se na 12ª posição da IDT. Então pare a execução do Bochs (com CONTROL+C) e digite o seguinte na janela do do emulador (não na do sistema em andamento):

info idt 0xc
Saída do Bochs após o pedido de informação do IDT

Saída do Bochs após o pedido de informação do IDT

Interrupt Gate target = 0x30:0x4b4 – Dessa resposta, tiraremos duas informações que nos levarão ao endereço real apontado pela IDT.

O “0x30” é o 16 bit segment selector e o “0x4b4” o offset.

O segmente selector é dividido conforme a figura abaixo:

Divisão do segment selector

Divisão do segment selector

Portanto, a informação que procuramos está no GDT, na posição 6 (se você não entende como 12 virou c e 110 virou 6, estude um pouco sobre bases hexadecimal e binária)

Passe agora o seguinte comando para o Bochs:

info gdt 0x6
Info GDT

Saída do Bochs após o pedido de informação do GDT (Global Description Table)

O valor 0x1000 é o linear address, que usaremos junto ao offset para encontrar o endereço real de onde fica a rotina de interrupção.

Se você tiver um interesse masoquista por conhecimento, pode entender todas essas siglas e posições lendo os manuais da Intel que encontram-se aqui. É nele que toda essa loucura de proteção do endereço real é explicada.

Finalmente, com linear addres + offset, temos o endereço real, que é 0x14b4.

Para confirmar isso, digite o seguinte na janela de emulação do Bochs:

u 0x14b4
Saída do Bochs após o pedido de informação do endereço 0x14b4

Saída do Bochs após o pedido de informação do endereço 0x14b4

A resposta é que na posição 0x14b4, encontra-se “push 0x0c” em assembly. Para confirmar que esse é o início da rotina de interrupção de estouro de pilha do Minix, temos que olhar para dois arquivos:

kernel/mpx386.s e kernel/protect.h

No primeiro, na linha 457, vemos o seguinte comando em assembly: push STACK_FAULT_VECTOR e no segundo, na linha 58, #define STACK_FAULT_VECTOR  12 .

Juntando tudo, verificamos que estamos exatamente na posição de início do código que o Minix executará caso uma interrupção de estouro de pilha ocorra.

Se você quiser brincar um pouco e ver uma interrupção ocorrendo, pode inserir uma pausa no Bochs usando:

b 0x14b4

Com isso, caso PC aponte para 0x14b4, o emulador será pausado.

Agora faça um programa eternamente recursivo como o abaixo para ver a interrupção ocorrendo:

#include <stdio.h>
#include <stdlib.h>
void meChama(int i){
 printf("iteracao %d\n", i++);
 meChama(i);
}

int main (int argc, const char * argv[]) {
 printf("iteracao 1\n");
 meChama(1);
 return 0;
}

Salve, compile, execute e veja a mágica.

Breackpoint em 0x14b4 mostrando sua mágica

Breackpoint em 0x14b4 mostrando sua mágica

A imagem acima mostra o exato momento em que o código que trata a interrupção de estouro de pilha começa a ser executado. Isso ocorre no momento em que o programa recursivo começaria a destruir toda sua memória e o processador (no caso, o emulador do processador) grita “PARA TUDO!!!” pro Minix e este passa a lidar com a bucha!

Tudo isso pode ser visto também nessa apresentação do Prezi que fizemos sobre estouro de pilha, mas que dependeu do entendimento da IDT e de todo o caminho tortuoso para achar o endereço real apontado por ela.

Anúncios

Deixe um comentário »

Nenhum comentário ainda.

RSS feed for comments on this post. TrackBack URI

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

Crie um website ou blog gratuito no WordPress.com.

%d blogueiros gostam disto: