Assembly é uma Linguagem mais próximo do hardware,
por isso é dito ser uma linguagem de baixo nível.
Softwares de alto nível:
Aqui é onde está a maioria dos usuários de computadores,
tipicamente lidando com aplicações gráficas, clicando em botões, menus,
minimizando, maximizando, fechando janelas, navegando na web e outras infinidades de coisas.
Nesse estágio, as coisas são bem simples e voltadas para
o usuário leigo.
Não é necessário saber absolutamente nada sobre o
funcionamento interno dos sistemas. E, de fato, a grande maioria dos usuários
não sabe.
Para o usuário, é tudo a mesma coisa, não importa se ele
esteja no Windows, MacOS, Linux, Android ou TV Digital: ele quer ver menus,
botões, clicar, arrastar, fechar e o mesmo de sempre.
Uma mera tela preta Terminal do
Linux, já seria motivo de espanto e repúdio.
A grande maioria das pessoas não tem motivos
para entender o que se passa por debaixo dos panos desses Software.
Softwares de baixo nível:
Linguagem de programação de baixo nível trata-se de uma linguagem de programação
que compreende as características da arquitetura do computador. Assim,
utiliza somente instruções do processador, para isso é necessário
conhecer os registradores da máquina. Nesse sentido, as linguagens de
baixo nível estão diretamente relacionadas com a arquitetura do
computador
Para programar em Assembly precisamos saber que tipo de arquitetura vamos
trabalhar.
Isso porque os comandos e códigos da
linguagem Assembly são diferentes e específicos para cada tipo de processador.
Ou seja, o nível de abstração da camada da linguagem Assembly é dependente do
sistema.
É tão dependente que até precisamos saber como é
organizada e o funcionamento da memória da máquina onde vamos programar.
A camada do código de máquina
Você já deve ter ouvido falar que tudo, absolutamente
tudo, em computação, é feito de números 1 e 0. E isso é verdade.
O computador (no sentido bem baixo da palavra, ou seja, o
metal, as peças eletrônicas) só entende e obedece a esses comandos, que nada
mais são que uma série de números binários (1’s e 0’s). Porém, quantas vezes
você já programou ou ouviu falar de alguém que programa em binário?
O objetivo da linguagem Assembly é suprir esse problema
da alta complexidade do binário.
Com o Assembly escrevemos de uma maneira mais ‘humana’,
mais fácil e compreensível, e esse código é convertido para o código de
máquina.
Assembly é eficiente:
Se você mandar duas pessoas, equipes ou empresas, fazerem
os mesmos softwares, verá que é impossível o código delas serem iguais.
Programar é raciocinar, é criatividade, depende do intelecto, experiência e
raciocínio dos programadores e chefes.
É por isso que existem navegadores Web bons e ruins,
Sistemas Operacionais lentos e rápidos, jogos bem feitos e mal feitos etc.
Isso tudo é eficiência: fazer um programa que rode mais
rápido, que consuma pouco processamento ou que exija o mínimo de memória
possível. E isso o Assembly é único.
Um programa bem feito em Assembly é simplesmente
imbatível.
Não é à toa que é Assembly é uma linguagem muito usada em
situações críticas, como em alguns trechos da construção de sistemas
operacionais, como o Linux (em sua grande parte é feito em C, mas em algumas
partes é necessário usar Assembly).
Compilador Assembly:
Você precisa Instalar o nasm pela sua Central de Aplicativos.Instalar Nasm Para o Ubuntu ou Debian (Com software-center instalado)
Código do Hello World em Assembly:
Crie um arquivo de texto com o nome "hello.asm" e escreve o seguinte código dentro dele:section .data msg db 'Olá Mundo', 0AH len equ $-msg ; Tamanho da string hello section .text global _start _start: mov edx, len ; Argumento que indica o tamanho da string mov ecx, msg ; Argumento que indica o endereço da string mov ebx, 1 ; Argumento que indica modo de escrita mov eax, 4 ; Interrupção de escrita (sys_write) int 80h ; Chamada da interrupção mov ebx, 0 ; Argumento da interrupção mov eax, 1 ; Interrupção exit (sys_exit) int 80h ; Chamada da interrupção
Caso seja 32 bits, vá no diretório do hello.asm e digite o seguinte código no terminal:
$ nasm -f elf32 hello.asm
Caso seja 64 bits, digite:
$ nasm -f elf64 hello.asm
Se você notar bem, foi criado um arquivo com extensão .o, é o hello.o
$ ld hello.o -o hello
$ ./hello
Sections & _start:
Quando um executável vai rodar, ele precisa saber a partir de onde, no código, ele começa a rodar.
Em programação, começar do começo não é algo comum.
Tendo em vista esses dados sobre a informação da ordem das coisas em um código, vamos falar neste tutorial de Assembly sobre as seções (sections) de um arquivo-fonte em Assembly.
Deixando seu código organizado
Programas feitos na linguagem de baixo nível Assembly tem uma características em comum: eles são grandes.Sim, programar em Assembly é escrever bastante, pois é uma linguagem totalmente crua, onde muito pouco 'existe' e muito, quase tudo, é necessário criar.
Para se fazer um simples programa de cálculos matemáticos simples (somar, subtrair etc) é necessário que fazer uma rotina, manualmente, para essa tarefa, usando somente as instruções nativas do processador.
Em linguagens de alto nível, como C e Java, isso já vem totalmente pronto.
Não é necessário criar nada, somente utilizar.
Então, mais que todas as outras linguagens, é necessário ter organização para programar em Assembly. Seu código deve ser legível, organizado e comentado.
Visando essa organização, existe um comando (ou simplesmente rótulo, ou marcador) chamado section, que serve para definirmos seções em nosso código.
Para declarar uma section fazemos:
section .nomeDaSecao
Como dividir um código Assembly: .data, .bss e .text
De uma maneira geral, os programadores Assembly utilizam três sections para organizar seus códigos. Seguir esses passos é interessante, visto que fará com que seus programas sejam organizados da maneira padrão, da maneira que é universalmente usada.Na .data section, como o nome sugere, é uma região do código que será usada para tratar as informações, os dados, as variáveis.
Nesse trecho (geralmente o inicial), declaramos e inicializamos as variáveis.
Fazemos algo parecido na .bss section, porém não inicializamos as informações.
Por fim, a .text section é o local onde irá ficar armazenado suas instruções, que irão trabalhar com os dados previamente declarados.
Essa é a única seção obrigatória, pois conterá a label (rótulo) _start, que é o local onde os executáveis são inicializados.
Se já estudou C, C++ ou Java, por exemplo, a _start seria o main().
Logo, o esqueleto dos códigos em Assembly é:
section .dat ;declaração e inicialização de dados section .bss ;declaração sem inicialização das informações que serão usadas section .text ;o programa começa a rodar aqui, a partir da _start
Se comunicando com o mundo externo: global
Como as memórias e processadores estão ficando cada vez mais modernos e maiores (em relação ao tamanho da memória), está possível, cada vez mais, usar linguagens de alto nível (principalmente o C), para tarefas que eram feitas exclusivamente em Assembly.Uma prova disso é o sistema operacional Linux, onde sua gigantesca parte é feita em C, com algumas pitadas em Assembly.
Essa pitada de Assembly no Kernel é justamente na parte que é necessária uma maior eficiência da máquina, pois como sabemos, em termos de eficiência nenhuma outra linguagem bate nossa amada linguagem.
Por isso, é bem comum a interação entre Assembly e outras linguagens. Um exemplo disso são os games de alto desempenho, que possuem rotinas feitas em Assembly, que se comunica com o resto do programa.
Uma maneira de fazer essa interação é através da diretiva (explicaremos o que é isso em breve) global.
A diretiva global mostra que o label relacionado é global, ou seja, é passível de uso externamente.
Geralmente usamos para declarar o label principal, o _start.
Portanto, o nosso esqueleto de código será:
section .dat ;declaração e inicialização de dados section .bss ;declaração sem inicialização das informações que serão usadas section .text global _start _start: ;o programa começa a rodar aqui, a partir daqui
O que é e como usar um Label (rótulo) em Assembly:
A tradução de label é 'rótulo', é uma nomenclatura que damos para dar nome a um trecho de código em Assembly.O label, por exemplo, serve (como o nome diz) para rotular, nomear uma seção do código, para que possamos definir uma região do código através de um rótulo, de um nome que quisermos.
Para criar uma label, basta digitar o nome desse rótulo seguido de dois pontos, ' : '.
Em seguida, escrevemos nossas linhas de código em Assembly.
A sintaxe é a seguinte, então:
label: ;aqui vem o código ;que vai ser nomeado ;de 'label'
Imagine que você criou uma rotina de códigos, suponha que você criou um trecho de código que vai repetir várias vezes durante seu programa em Assembly. Ou seja, esse código se repete, você vai usar mais de uma vez.
Vamos então criar um label chamado 'rotinaBase'.
rotinaBase: ;código
O que o label faz é nomear essa porção de linhas de código.
Para executar elas, em vez de escrever todas elas de novo em outra parte, você apenas se refere a "rotinaBase", e o trecho de código que você usou abaixo da label 'rotinaBase' será executado.
Lembrando que a linguagem Assembly está em baixo nível, ela sempre trata tudo em relação aos endereços na memória.Os labels estão intrinsecamente ligados com endereços de memória.
Um label serve para representar o endereço de um determinado trecho no código (ou para inicializar variáveis e constantes que podem ter seus endereços realocados).
Assim, se usarmos esse trecho de código várias vezes, em vez de repeti-lo basta voltar ao ponto (endereço) na memória que tem esses códigos.
Porém, é complicado para os humanos tratarem os endereços de memórias como números (em binário, hexadecimal ou mesmo decimal), por isso damos um nome a esse endereço de memória, um rótulo, e passamos a chamar esse local da memória pelo seu label. Bem mais simples, não?
No nosso código do Hello World em Assembly, usamos o label '_start', que serve para definir para o NASM onde vai começar nosso programa.
Como outro exemplo do uso de label em nossos códigos Assembly, vamos supor que durante a execução de um programa seja necessário incrementar uma variável 'numero' várias vezes.
O código para incrementar é:
inc numero ;numero++
Onde 'inc' é um mnemônico, ou seja, representa a operação de incrementação (adicionar +1 à variável 'numero'). Vamos criar um label para definir esse trecho de código, a label: 'incrementa'.
Ela ficaria assim:
incrementa: inc numero ;incrementa 'numero' em uma unidade
Pronto, agora podemos incrementar a variável número apenas invocando o label.
Labels internas ou Labels locais
O uso de labels é altamente recomendável, visto que os programas em baixo nível sempre são enormes, com códigos 'obscuros', números hexadecimais e outras complicações visuais.Em sistemas mais complexos, onde é necessário o uso de centenas ou milhares de linhas de código, será interessante usar labels internas.
Você usará labels que vão representar centenas de linhas de código, e pode ser necessário usar labels dentro destas labels, e provavelmente que tenham o mesmo nome.
O NASM, que é o Assembler que estamos usando, permite a definição de labels locais.
Para isso, basta colocar um ponto, ' . ', antes do nome da label.
labelNormal -> label normal, sem ponto
.labelInterna -> label local, com ponto, ela está dentro('pertence) a label 'labelNormal'
Por exemplo, uma representação de um código que duas labels internas, de mesmo nome, mas em locais diferentes, que fazem a mesma coisa (incrementar), mas incrementam variáveis diferentes:
trecho1: ;trecho 1 do código .incrementa: inc numero1 ;continuação trecho 1 trecho2: ;trecho 2 do código .incrementa: inc numero2 ;continuação do trecho 2
Note que uma label local se refere a label 'geral', imediatamente superior.
Cuidado para não se confundir.
Define - Como alocar memória Assembly
&
RES - como reservar memória
Se você estudou somente linguagens de altíssimo nível, como as de linguagens de script, com certeza nunca se preocupou em alocar memória, pois é tudo feito automaticamente por debaixo dos panos.
Se estudou linguagens como C ou Java, você alocava espaço na memória ao declarar variáveis e estruturas (em C é possível ainda, a alocação dinâmica de memória).
Nesse tutorial de nosso curso de Assembly, vamos aprender como reservar espaço em disco em Assembly, ver quais as diferenças e peculiaridades nessa linguagem de baixo nível.
Alocação de memória em programação
Em outras linguagens de programação, para declarar variáveis precisávamos definir o tipo antes.Por exemplo, em C ou C++, escrevíamos 'int' para inteiros, 'float' ou 'double' para decimais, 'char' para caracteres, dentre outros tipos.
Ao fazermos isso, sem saber (diferente do Assembly, em que vemos claramente como as coisas são feitas), estamos dizendo muito mais do que simplesmente a alocação de memória em si.
O resultado de uma operação entre um inteiro e um decimal não é totalmente previsível, depende da variável em que vamos armazenar, da linguagem e de outras regra específicas.
Quando declaramos uma variável do tipo double ou float, já fica sub-entendido que haverá uma vírgula (ou ponto), representado sua parte decimal. Além disso, há divisões no espaço alocado de memória, para armazenar a parte inteira e a parte decimal.
Enfim, acontece muito mais do que simplesmente reservar um espaço de memória. Muitas rotinas úteis, que facilitam a vida de programador acontecem por debaixo dos panos.
Alocação de memória em Assembly - A diretiva define
Obviamente, em Assembly as coisas são um pouco diferente.Essas coisas que atuam sem o conhecimento do programador simplesmente não existem, e o profissional que programa em Assembly ficará a cargo de tudo.
Em Assembly, você realmente irá alocar espaço em memória. E somente isso.
Por exemplo, usamos o comando ADD para adicionar um número a outro. Mas ele não vai simplesmente adicionar todos e quais números automaticamente como costumamos fazer em outras linguagens.
Se o resultado der mais de dois dígitos, por exemplo, você terá que fazer uma rotina para exibir esses dois dígitos (sabe quando você soma no papel, fazendo continha e o valor da soma dá mais que 9, aí 'vai 1' ou 'sobe 1' ? é algo parecido) ; ao somar, ter cuidado para saber se somou o caractere '1' ou realmente o número 1. Case seja caractere, ou queira exibir, terá que fazer alterações, e por aí vai.
Como enfatizamos, Assembly é em baixo nível.
Trabalhamos com bits e bytes. E nesse nível, as coisas não vem prontas.
O programador Assembly é que o tem o poder e responsabilidade de absolutamente tudo. Por isso, ao alocar memória, temos que definir o número de bytes que vamos usar.
Vamos usar as seguintes variações da diretiva define: DB, DW, DD, DQ e DT.
Eles significam e alocam determinados número de bytes, veja:
DB = Define Byte -> aloca 1 byte
DW = Define Word -> aloca 2 bytes
DD = Define Doubleword -> aloca 4 bytes
DQ = Define Quadword -> aloca 8 bytes
DT = Define Ten -> aloca 10 bytes
Sabendo disso, poderemos agora mostrar como é a sintaxe de uma instrução em Assembly para alocar memória:
Nome_da_Variavel diretiva_define valor
Por exemplo, para alocar espaço para o caractere 'A', fazemos:
letra1 DB 'A'
Lembramos que, na verdade, embora tenhamos escrito o caractere 'A', tudo são números.
Então, como na tabela ASCII o valor de 'A', em hexadecimal é 41, poderíamos ter feito:
letra1 DB 41H
Colocamos a letra H ao final do número para dizer que estamos representando em Hexadecimal.
Se fossemos colocar em binário, temos que colocar a letra B ao final:
letra1 DB 01000001B
Um pouco de matemática
Em Assembly, trabalhamos sempre com bytes, onde um byte equivale a 8 bites.Cada bit desse pode ser 0 ou 1, então podemos representar até: 2^8 = 256 caracteres com um byte.
Em Hexadecimal, podemos representar esses 256 caracteres usando os números 00H até FFH.
Ou seja, 41H caberia em um byte, pois é menor que FFH.
Agora 2112H só caberia em dois bytes, onde um armazenaríamos o byte 12H e no outro o byte 21H.
Vamos armazenar uma senha na variável 'senha', ela conterá 4 dígitos decimais: 1234
Esse número, em hexadecimal equivalem a 4660H.
Precisamos, então, definir dois bytes, ou uma palavra (word). Um byte armazena o 60H e o outro armazena o 46H.
Para alocar memória para essa senha, faríamos:
senha DW 466H
Outras maneiras de alocar memória em Assembly
E se quiséssemos alocar uma palavra, como 'curso', por exemplo?
Poderíamos alocar letra por letra:
letra1 DB 'c'
letra2 DB 'u'
letra3 DB 'r'
letra4 DB 's'
letra5 DB 'o'
Porém, seria muito trabalhoso, e há maneira mais fáceis de se fazer isso.
Em vez de ter que dar um nome para cada letra (isso não faz o menor sentido!), poderíamos dar um nome só para o conjunto de letras:
curso DB 'c'
DB 'u'
DB 'r'
DB 's'
DB 'o'
E sempre que usarmos a variável curso, o Assembly saberá que se trata de conjunto de caracteres.
A maneira mais prática e utilizada para armazenar uma string, é utilizando a define DB e escrevendo uma string (que nada mais é que um texto, um conjunto de caracteres).
O Assembly irá alocar, automaticamente, todos os caracteres, como se tivéssemos feito o exemplo passado.
No exemplo do "Hello, wolrd" em Assembly, Bem mais prático, não?
Reservando memória em Assembly
Até agora, usando a diretiva define e suas variações (DB, DW, DD, DQ e DT), alocamos memória em Assembly para armazenar e INICIALIZAR variáveis!
Porém, nem sempre vamos inicializar, apenas queremos alocar.
Isso é comum para armazenar variáveis cujos valores serão fornecidos posteriormente, pelo seu programa, pelo usuário ou um dispositivo de entrada e saída.
Para reservar memória, usamos a diretiva RES, ao mesmo molde da diretiva DEFINE:
RESB = Reserve Byte -> reserva 1 byte
RESW = Reserve Word -> reserva 2 bytes
RESD = Reserve Doubleword -> reserva 4 bytes
RESQ = Reserve Quadword -> reserva 8 bytes
REST = Reserve Ten -> reserva 10 bytes
A sintaxe é um pouco diferente da DEFINE, já que não vamos inicializar.
Assim, em vez de valor inicial, temos que dizer quanto de espaço queremos reservar, dependendo da diretiva que usamos.
Sintaxe para reservar memória:
nome_da_variavel diretiva_res numero_de_unidades
Por exemplo:
variavel1 RESB 1 ; nesse caso, reservamos apenas 1 byte
variavel2 RESB 2 ; aqui, reservamos 2 bytes
variavel3 RESW 3 ; 3 palavras são reservadas, o que nos dá 3*2 = 6 bytes
variavel4 REST 10 ; reservamos 10 unidades, de 10 bytes cada
Iremos continuar falando sobre a alocação de memória.
No caso, falaremos de alocação de blocos contínuos de memória, popularmente conhecidos como vetores (C, C++) ou arrays (Java).
Lembramos que vetores e arrays em Assembly são um vasto conteúdo, há uma série de possibilidades e conceitos por trás desta ideia, e ainda veremos muito sobre o assunto.Porém, este tutorial está na seção básica e se destina a apresentar as ideias iniciais, alocação e inicialização de elementos de um vetor.
já vimos como declarar variáveis, dando um nome para elas e definindo o tanto de bytes que iremos separar em memória somente para aquelas variáveis, através de comandos como DB e DW.
Mas se notar bem, alocamos alguns espaços, manualmente.
E se for necessário alocar mil bytes diferentes, para armazenar números quando você for projetar o hardware de um microondas?
Um sistema como um relógio digital é complexo e pode usar dezenas de milhares de bytes facilmente, e como os recursos são poucos, é necessário usar a linguagem Assembly.
E é claro que você não vai manusear cada byte desses (embora programadores Assembly sejam conhecidos por serem escovadores de bits), e é para isso que existem os arrays, também conhecidos por vetores.
Um vetor, ou array, nada mais é que um bloco enorme de bytes, onde cada bloco é usado como uma variável, digamos assim, pois trabalhamos diretamente com bytes de memória, não importa se seja pra um inteiro, caractere ou booleano, pois essas ideias são de linguagens de alto nível, que abstraem diversos conceitos do que realmente ocorre por debaixo dos panos.
Para nós, vetor ou array em Assembly é um bloco de bytes, geralmente grande, para que possamos manipular uma quantidade maior de informações de uma maneira bem mais simples, óbvia e lógica.
No decorrer de nosso curso nos depararemos diversas vezes com arrays.
Para alocar um bloco de vários bytes ainda utilizaremos a define, mas precisamos dizer quantas vezes esta alocação deve ocorrer.
Para dizermos o tanto de vezes (de blocos de bytes) que queremos alocar, vamos usar a diretiva TIMES (que pode ser traduzida como vezes . 3 times -> 3 vezes, 4 times-> 4 vezes).
Em seguida, devemos dizer o número de vezes que a define vai se repetir.
Após nomear, usar a TIMES, dizer o tanto de vezes que a alocação de bytes deve ser feita, devemos obviamente dizer quantos bytes vão ser alocados por vez.
E como sabemos, para alocar bytes usamos os comandos DB, DW, DD, DQ e DT.
E por fim, devemos dar um valor inicial para esses bytes do bloco de memória.
Você pode alocar 1 milhão de blocos de DT (cada DT aloca 10 bytes), e inicializar cada um deles com um valor numérico, de forma totalmente automática.
Assim, a sintaxe geral para se declarar um vetor/array em Assembly é:
Vamos criar um array de nome "vetor", cada elemento do vetor vai ser alocado através de um DB, esse vetor terá 10 elementos (então vamos repetir 10 vezes a alocação DB) e vamos inicializar todos os elementos de nosso array com valor 0:
Agora vamos declarar um vetor de nome "array", ele será composto de 20 elementos do tipo word (2 bytes cada), e será inicializado com o valor hexadecimal FFH:
Por exemplo, vamos supor que nossa variável "elemento1' ocupe um byte, vamos dizer que na posição "x" de memória:
Se formos, em seguida, alocar a variável "elemento2" que é do tipo e word e ocupa 2 bytes, ela vai estar na posição "x+1" de memória, pois na posição "x" está o "elemento1" e ele ocupa 1 byte:
A próxima variável que declararmos vai estar na posição "x+3", pois o local "x" é ocupado por "elemento1" e os dois bytes seguintes é ocupado por "elemento2", concorda?
Vamos fazer a seguinte declaração:
Note que o "vetor1" ocupa 10x1=10 bytes, pois ele aloca 10 elementos do tipo byte (DB).
E como dissemos, o "vetor1" vai inicial no local de memória "x+3", como ele ocupa 10 bytes, o próximo vetor vai se iniciar na posição "x+3+10", ou seja, "vetor2" começa na posição "x+13", ok?
Agora vamos analisar "vetor2", ele declara um bloco de memória de 20 elementos do tipo WORD, onde cada um destes ocupada 2 bytes. Então "vetor2" ocupada 20x2=40 bytes.
Isso é comum para armazenar variáveis cujos valores serão fornecidos posteriormente, pelo seu programa, pelo usuário ou um dispositivo de entrada e saída.
Para reservar memória, usamos a diretiva RES, ao mesmo molde da diretiva DEFINE:
RESB = Reserve Byte -> reserva 1 byte
RESW = Reserve Word -> reserva 2 bytes
RESD = Reserve Doubleword -> reserva 4 bytes
RESQ = Reserve Quadword -> reserva 8 bytes
REST = Reserve Ten -> reserva 10 bytes
A sintaxe é um pouco diferente da DEFINE, já que não vamos inicializar.
Assim, em vez de valor inicial, temos que dizer quanto de espaço queremos reservar, dependendo da diretiva que usamos.
Sintaxe para reservar memória:
nome_da_variavel diretiva_res numero_de_unidades
Por exemplo:
variavel1 RESB 1 ; nesse caso, reservamos apenas 1 byte
variavel2 RESB 2 ; aqui, reservamos 2 bytes
variavel3 RESW 3 ; 3 palavras são reservadas, o que nos dá 3*2 = 6 bytes
variavel4 REST 10 ; reservamos 10 unidades, de 10 bytes cada
Arrays (vetores) em Assembly
No caso, falaremos de alocação de blocos contínuos de memória, popularmente conhecidos como vetores (C, C++) ou arrays (Java).
Lembramos que vetores e arrays em Assembly são um vasto conteúdo, há uma série de possibilidades e conceitos por trás desta ideia, e ainda veremos muito sobre o assunto.Porém, este tutorial está na seção básica e se destina a apresentar as ideias iniciais, alocação e inicialização de elementos de um vetor.
Array ou Vetor em Assembly
Iremos continuar falando sobre alocar memória em Assembly.já vimos como declarar variáveis, dando um nome para elas e definindo o tanto de bytes que iremos separar em memória somente para aquelas variáveis, através de comandos como DB e DW.
Mas se notar bem, alocamos alguns espaços, manualmente.
E se for necessário alocar mil bytes diferentes, para armazenar números quando você for projetar o hardware de um microondas?
Um sistema como um relógio digital é complexo e pode usar dezenas de milhares de bytes facilmente, e como os recursos são poucos, é necessário usar a linguagem Assembly.
E é claro que você não vai manusear cada byte desses (embora programadores Assembly sejam conhecidos por serem escovadores de bits), e é para isso que existem os arrays, também conhecidos por vetores.
Um vetor, ou array, nada mais é que um bloco enorme de bytes, onde cada bloco é usado como uma variável, digamos assim, pois trabalhamos diretamente com bytes de memória, não importa se seja pra um inteiro, caractere ou booleano, pois essas ideias são de linguagens de alto nível, que abstraem diversos conceitos do que realmente ocorre por debaixo dos panos.
Para nós, vetor ou array em Assembly é um bloco de bytes, geralmente grande, para que possamos manipular uma quantidade maior de informações de uma maneira bem mais simples, óbvia e lógica.
No decorrer de nosso curso nos depararemos diversas vezes com arrays.
A diretiva TIMES: Como declarar e inicializar um vetor/array em Assembly
Para alocarmos memória usamos a diretiva define, mais conhecida pelas abreviações DW, DD, DQ etc, e principalmente pela DB (define byte).Para alocar um bloco de vários bytes ainda utilizaremos a define, mas precisamos dizer quantas vezes esta alocação deve ocorrer.
Para dizermos o tanto de vezes (de blocos de bytes) que queremos alocar, vamos usar a diretiva TIMES (que pode ser traduzida como vezes . 3 times -> 3 vezes, 4 times-> 4 vezes).
Em seguida, devemos dizer o número de vezes que a define vai se repetir.
Após nomear, usar a TIMES, dizer o tanto de vezes que a alocação de bytes deve ser feita, devemos obviamente dizer quantos bytes vão ser alocados por vez.
E como sabemos, para alocar bytes usamos os comandos DB, DW, DD, DQ e DT.
E por fim, devemos dar um valor inicial para esses bytes do bloco de memória.
Você pode alocar 1 milhão de blocos de DT (cada DT aloca 10 bytes), e inicializar cada um deles com um valor numérico, de forma totalmente automática.
Assim, a sintaxe geral para se declarar um vetor/array em Assembly é:
nomeDoBloco TIMES numeroDeVezes diretivaDEFINE valorInicial
Vamos criar um array de nome "vetor", cada elemento do vetor vai ser alocado através de um DB, esse vetor terá 10 elementos (então vamos repetir 10 vezes a alocação DB) e vamos inicializar todos os elementos de nosso array com valor 0:
vetor TIMES 10 DB 0
Agora vamos declarar um vetor de nome "array", ele será composto de 20 elementos do tipo word (2 bytes cada), e será inicializado com o valor hexadecimal FFH:
array TIMES 20 DW FFH
Espaços contíguos de memória Assembly
Um fato interessante que ocorre na linguagem de programação Assembly é que, ao reservar e alocar espaços de memória, isso é geralmente feito de modo que os blocos de memória sejam contíguos, ou seja, vizinhos.Por exemplo, vamos supor que nossa variável "elemento1' ocupe um byte, vamos dizer que na posição "x" de memória:
elemento1 DB 00H
Se formos, em seguida, alocar a variável "elemento2" que é do tipo e word e ocupa 2 bytes, ela vai estar na posição "x+1" de memória, pois na posição "x" está o "elemento1" e ele ocupa 1 byte:
A próxima variável que declararmos vai estar na posição "x+3", pois o local "x" é ocupado por "elemento1" e os dois bytes seguintes é ocupado por "elemento2", concorda?
Vamos fazer a seguinte declaração:
elemento1 DB 00H elemento2 DW 01H vetor1 TIMES 10 DB 0 vetor2 TIMES 20 DW 0 elemento3 DD 0
Note que o "vetor1" ocupa 10x1=10 bytes, pois ele aloca 10 elementos do tipo byte (DB).
E como dissemos, o "vetor1" vai inicial no local de memória "x+3", como ele ocupa 10 bytes, o próximo vetor vai se iniciar na posição "x+3+10", ou seja, "vetor2" começa na posição "x+13", ok?
Agora vamos analisar "vetor2", ele declara um bloco de memória de 20 elementos do tipo WORD, onde cada um destes ocupada 2 bytes. Então "vetor2" ocupada 20x2=40 bytes.
"elemento3" ocupa 4 bytes
x+13+40=x+53
Nenhum comentário:
Postar um comentário