Informática Numaboa - Tutoriais e Programação
Trabalhando com estruturas (masm)
Ter 20 Jan 2009 21:24 |
- Detalhes
- Categoria: Assembly Numaboa (antigo oiciliS)
- Atualização: Domingo, 21 Junho 2009 18:45
- Autor: vovó Vicki
- Acessos: 6410
Quando se escreve código para Windows, é comum manusear dados em bloco para alguns requisitos de codificação. O método mais comum é usar uma estrutura para agrupar os dados de forma que possam ser endereçados como uma unidade.
Estruturas
Uma estrutura é constituída por membros que têm um tamanho fixo para armazenar os dados. Na estrutura RECT, muito utilizada, existem quatro membros de tamanho DWORD.
RECT STRUCT left DWORD ? top DWORD ? right DWORD ? bottom DWORD ? RECT ENDS
A notação para cada membro é: nome do membro, tamanho do dado e especificador. Na maior parte das vezes o especificador é um ponto de interrogação (?), significando que o membro não foi inicializado com um valor.
A estrutura é colocada na memória como uma sequência de membros. No caso da estrutura RECT, ela é escrita na memória como uma sequência de quatro membros de tamanho DWORD. Os membros de uma estrutura podem ser preenchidos de várias maneiras diferentes, dependendo da modo como a estrutura foi originalmente definida.
Se ela tiver sido alocada na seção .DATA, eles podem ser inicializados com valores predefinidos. Se tiver sido alocada na pilha, como uma variável local de um procedimento, os valores precisam ser inseridos nesta estrutura através de codificação. Por exemplo:
É preciso salientar que um membro de uma estrutura é um operando de memória, o que significa que você não pode transferir diretamente outro operando de memória para ele. É preciso usar um registrador para copiá-lo ou usar os mnemônicos de pilha push/pop.
Numa chamada com a diretiva invoke podemos nos referir à estrutura preenchida como uma unidade com ADDR Rct. Se uma chamada de API necessitar do endereço de uma estrutura, você deve preencher a estrutura com os valores requeridos e depois chamar a API de acordo com a seguinte sintaxe:
invoke chamadaAPI, parametro1, parametro2, ADDR Rct
Se você escrever um procedimento para o qual você queira passar os valores de uma estrutura, pode passar esta estrutura usando os tipos de dados da estrutura no procedimento.
No procedimento que recebe RECT como parâmetro, cada um dos membros pode ser acessado através do nome. Você chama o procedimento da seguinte forma:
Estruturas aninhadas
Um método muito comum no Windows 32 bits é o uso de estruturas aninhadas. O MASM possui uma notação que lida com este tipo de construção. Se você precisar de uma estrutura que possui múltiplas estruturas no seu interior, a coisa funciona assim:
MinhaEstruAninhada STRUCT item1 RECT <> item2 POINT <> MinhaEstruAninhada ENDS
Esta estrutura usa a estrutura RECT (mostrada anteriormente) e a seguinte estrutura POINT:
POINT STRUCT x DWORD ? y DWORD ? POINT ENDS
Neste caso, existem seis membros na estrutura "MinhaEstruAninhada", quatro da estrutura RECT e dois da estrutura POINT. Alocada na pilha, tem o seguinte aspecto:
Os seis membros desta estrutura são:
mea.item1.left mea.item1.top mea.item1.right mea.item1.bottom mea.item2.x mea.item2.y
A notação mea.item2.x significa a estrutura alocada mea, seu segundo item (item2) e o primeiro item da estrutura POINT (x).
As estruturas podem ser aninhadas em diversas profundidades, mas todas usam esta mesma notação e a mesma lógica.
Uso avançado de estruturas
Cada vez mais existe a necessidade de manusear estruturas que são passadas como um endereço e este tipo de codificação está-se tornando comum no design de código Windows. O MASM tem uma notação especializada para facilitar o manuseio.
Se, por exemplo, você precisasse passar o endereço de uma estrutura RECT para um procedimento, normalmente iria fazer a chamada da seguinte maneira:
No final do procedimento onde foi chamada esta função, normalmente haveria algo parecido com o seguinte:
Com uma estrutura simples como a RECT, você pode endereçar manualmente cada um dos parâmetros colocando o endereço num registrador e escrevendo na localização de cada membro:
Isto funciona muito bem, porém, com estruturas mais complexas, fica mais difícil trabalhar e mais fácil errar. A alternativa é usar um método que o MASM possui para endereçar cada um dos membros: a diretiva ASSUME.
Esta diretiva informa o assembler que o registrador EAX deve ser tratado como uma estrutura RECT. O ASSUME eax:nothing informa o assembler que é para parar de tratar o registrador como uma estrutura RECT.
Há uma notação alternativa onde você pode fazer um "type cast" para cada membro:
A vantagem desta técnica é que ela usa a conveniência e a confiabilidade de uma estrutura, de modo que você não precisa calcular o offset de cada membro, além de usar os nomes normais dos membros. A desvantagem desta técnica é que ela usa um registrador, o que nem sempre é conveniente. Se o uso do registrador for um problema, você precisará alocar variáveis LOCAIS e copiar os dados de cada membro requerido para estas variáveis.
Finalmentes
O assunto parece ser coisa de outro planeta? Se for este o seu caso, ignore este tutorial por enquanto. Em outros tutoriais sobre Assembly estas técnicas serão utilizadas e haverá links para este tutorial. Aí a coisa fica um pouco mais clara, mas se você quiser matar a curiosidade agora mesmo, veja uma aplicação prática no tutorial "Pintando texto".
Abraços da vó Vicki