Informática Numaboa - Tutoriais e Programação
Por onde começar
Sex 15 Dez 2006 20:20 |
- Detalhes
- Categoria: Assembly Numaboa (antigo oiciliS)
- Atualização: Segunda, 09 Março 2009 20:29
- Autor: vovó Vicki
- Acessos: 40567
Assemble vem do Inglês e significa construir, juntar partes; é daí que vem o nome de uma linguagem de programação, o ASSEMBLY. Assembler significa construtor e é o nome que se dá a programas que "juntam partes", que "constroem" executáveis. É por isto que não é possível escrever um programa em assembler (como se costuma ver por aí): o programa é escrito em Assembly e depois pode ser transformado num executável por um assembler
Por onde começar é aquela parte inicial, chata pra caramba, mas que não adianta ignorar porque vai fazer falta mais tarde. Neste texto você vai ter a oportunidade de conhecer um pouco do MASM e da estrutura de um programa.
Para se comunicar com um assembler são utilizadas algumas convenções que o programa exige para poder executar as tarefas desejadas. Cada assembler tem suas próprias convenções. Nestes tutoriais vamos utilizar o MASM32 como assembler, mas você pode usar qualquer outro da sua escolha. As diferenças são pequenas e é fácil adaptar o código.
O assembler
Antes de mais nada, faça o download do macroassembler da Microsoft, o MASM 32 versão 9, na seção de downloads da Aldeia. Procure na categoria Informática|Compiladores/Decompiladores. Descompacte o arquivo zipado num diretório (quem "fala" Assembly não usa pastas, usa diretórios!) da sua escolha e clique em /seuDiretório/QEDITOR.EXE. Esta é a interface de edição de programação - não é cheia de nove horas porque programadores assembly estão acostumados a escovar bits e a fazer a maior parte do trabalho na unha sem muita frescura.
Muito bem. O editor está à disposição e aí vem a pergunta: o que fazer agora? tô afim de começar! Hehehe... lembra da parte inicial, chata pra caramba? Pois é esta aqui. Tenha um pouco de paciência e, por enquanto, feche o editor e leia o resto do texto. Depois a gente conversa.
A sequência do trabalho
Quando se escreve um programa, na realidade se escreve um texto que contém um roteiro que precisa ser transformado num programa. Esta transformação é feita em duas etapas. Primeiro, o texto precisa ser transformado num novo roteiro que contenha instruções para a CPU. Esta primeira tradução produz os assim chamados arquivos objeto. O programa que produz arquivos objeto é chamado de assembler ou compilador. Os arquivos objeto, por sua vez, servem de fonte para outro tipo de programa: o linker. Os linkers adicionam referências de endereços aos arquivos objeto e os transformam em arquivos executáveis, a versão final do seu programa. Resumindo as etapas, tem-se o seguinte:
Arquivo Texto (.ASM) ---> Arquivo Objeto (.OBJ) ---> Arquivo Executável (.EXE) Editor de Texto Assembler (compilador) Linker
O MASM é um aplicativo que pode coordenar o seu trabalho: possui um editor de texto, um compilador e um linker. Através da janela do MASM é possível gerenciar todo o processo de produção de um programa.
Você pode escrever seu texto (ou script) em qualquer editor de texto, até com o bloco de notas do Windows. Como usaremos o MASM, podemos usar o editor de texto do próprio. Se escrevermos uma receita de bolo no editor de texto e pedirmos para o MASM (compilador+linker) transformá-lo num programa... hmmmm... o MASM vai ficar perdidinho da silva. É preciso criar um texto que o MASM entenda e, o que é mais importante, obedecendo uma determinada estrutura.
A estrutura de um programa
A primeira informação que o MASM precisa para poder trabalhar é o tipo de CPU para a qual o programa se destina. Isto é necessário para que o compilador possa escolher o conjunto de instruções compatíveis com a CPU. Como pretendemos produzir programas de 32 bits, indicamos o conjunto de instruções como sendo do tipo 80386 em diante (80386, 80486, Pentium, etc). Trabalhar com o conjunto de instruções do 386 costuma ser mais do que suficiente. Como é que passamos essa informação para o compilador? Usando uma diretiva apropriada:
.386 ---> para processadores do tipo 80386 .486 ---> para processadores do tipo 80486
Puxa vida, por enquanto, nada de programa. Ainda precisamos indicar qual é o modelo de memória que deve ser usado. Um executável é carregado na memória de acordo com o modelo de memória definido durante a compilação. Na época dos computadores de 16 bits, o programa era carregado na memória em segmentos de tamanho predefinido. Era uma complicação danada gerenciar a execução do programa: para cada endereço era necessário indicar o segmento correspondente e saltar de um segmento para outro - parecia soluço e "comia" um monte de processamento. Com o advento dos 32 bits, os executáveis passaram a ser carregados na memória em endereços contíguos. Imagine um segmento único de memória contendo o executável, uma tripa enorme com a sequência de instruções. Este modelo de memória foi denominado FLAT, ou seja, modelo plano ou contínuo. Então, lá vai mais uma diretiva:
.MODEL FLAT
Qualquer programa, com toda certeza (tem tanta certeza assim?) vai realizar algum trabalho, ou seja, vai ter funções. As funções geralmente precisam de dados para executar uma tarefa. Estes dados podem ser gerados dentro da própria função ou serem enviados para elas. Dados enviados a uma função são chamados de parâmetros. A forma de mandar estes parâmetros também precisa ser definida previamente: se houver mais de um parâmetro, podemos enviá-los de frente para trás ou de trás para frente, ou seja, da esquerda para a direita ou da direita para a esquerda. Veja um exemplo: suponha que uma função espere receber dois parâmetros (param1 e param2). Podemos enviá-los na sequência param1, param2 ou na sequência param2, param1. A primeira convenção de passagem de parâmetros é conhecida como PASCAL e a segunda como convenção C.
Os parâmetros recebidos são guardados temporariamente num registrador da CPU chamado de pilha (stack). Imagine a pilha como uma pilha de caixas de sabão em pó no supermercado. À medida que você colocar novas caixas na pilha, a pilha vai crescendo; à medida que tira, a pilha vai encolhendo; se você tirar uma caixa do meio da pilha, as caixas vão cair. Como o conteúdo da pilha é alterado quando uma função é chamada ou quando a própria função alterá-lo, é preciso fazer um ajuste de pilha em cada retorno de função... senão a pilha "cai" e o programa dá pau. Na convenção de passagem de parâmetros do tipo Pascal, a função chamada é a responsável pelo ajuste da pilha antes do retorno. Na convenção C, a rotina chamadora é a responsável.
Existe uma terceira convenção de passagem de parâmetros denominada STDCALL (abreviação de STanDard CALL - chamada padrão). Usando esta convenção, os parâmetros são enviados da direita para a esquerda (como na convenção C) mas a função chamada é a responsável pelo ajuste da pilha. A STDCALL é um híbrido das convenções Pascal e C.
Os sistemas win32 utilizam exclusivamente a convenção de passagem de parâmetros STDCALL. Podemos e devemos completar a diretiva acima com:
.MODEL FLAT, STDCALL
Na maioria das vezes, um programa precisa de dados inicializados (com valores definidos) para poder começar a funcionar. São coisas do tipo nome do aplicativo, título da janela principal, etc. Para indicar ao MASM que vamos listar nomes de variáveis e seus respectivos valores, usamos a diretiva .DATA. Tudo que o compilador encontrar nas linhas subsequentes, até encontrar outra diretiva, ele vai considerar como variáveis (dados) inicializados.
Também podemos preparar variáveis não inicializadas, ou seja, fazemos com que o assembler ponha determinados nomes de variáveis na lista de variáveis, mas sem valores definidos. Estes dados não inicializados podem ser usados posteriormente pelo código. A diretiva .DATA? faz a indicação.
Variáveis, como o próprio nome indica, podem ter seus valores alterados. Num determinado projeto pode ser que sejam necessários dados de valores fixos, as assim chamadas constantes. Neste caso, utilizamos a diretiva .CONST.
Todos estes dados, indicados antes do programa propriamente dito, podem ser usados em qualquer ponto do código. Tanto faz se estamos no módulo principal ou em alguma subrotina (função) - estes dados estão sempre disponíveis e acessíveis. São os chamados dados globais (variáveis e constantes). Enquanto o programa estiver sendo executado, estes dados ficam preservados. Só são destruídos quando o programa termina.
Ufa! Finalmente chegamos no miolo do programa. É onde deve ficar o código que indica como nosso programa deve se comportar e o que deve realizar. A diretiva usada não poderia ser outra: .CODE indica o início do nosso código. Só que esta é a última diretiva da estrutura e o assembler não tem como saber onde ela termina. Estabelecemos então o limite com um rótulo seguido por dois pontos. O
.CODE ---> Início do código inicio: ---> Rótulo indicando o início da área de código ... (seu código) end inicio ---> Fim da área de código
Resumindo, a estrutura que o MASM entende e aceita para assemblar e linkar é a seguinte:
.386 .MODEL FLAT, STDCALL .DATA ... (aqui vão os dados inicializados) .DATA? ... (aqui vão os dados não inicializados) .CONST ... (aqui ficam as constantes) .CODE inicio: ... (aqui está todo o código do programa) end inicio
Palpites da vó
Por enquanto, é só. Depois que você estiver familiarizado com o Assembly, vai usar esta estrutura de diretivas automaticamente, sem problema algum - mas sempre é bom revisar o que realmente significam e como devem ser utilizadas. Para você que está começando, então isto tudo é novidade. Dê mais uma lida no texto e fixe bem os conceitos para evitar futuras dores de cabeça com programas "mal comportados".
- Anterior
- Próximo >>