Programando em
ASSEMBLY Uma introdução à programação em Assembly
Arthur Xavier Gomes Ribeiro
Índice Introdução ............................................. Registradores .......................................... Instrução MOV .......................................... Instrução LEA .......................................... Interrupções ........................................... Instruções ADD, SUB, MUL e DIV ......................... Instrução JMP .......................................... O Comando CMP .......................................... A Pilha, o PUSH e o POP ................................ O DEBUG do DOS ......................................... Primeiro Programa ......................................
4 4 5 5 5 6 7 7 8 8 9
A Estrutura de um programa .EXE ........................ Hello World ............................................ Turbo Assembler ........................................ Apêndice: Primeiro Programa ............................
10 11 11 12
Introdução Assembly é uma linguagem de baixo nível, ou seja, ela se comunica diretamente com o processador, sem nenhum tipo de intermediário, apenas o Sistema Operacional . A linguagem Assembly é uma notação que pode ser compreendida para os opcodes (códigos operacionais da máquina). As instruções dadas ao processador na linguagem Assembly são chamadas de Mnemônicos, pois representam palavras para auxiliar a memorização dos comandos. Assembly não é uma linguagem compilada, e sim montada usando-se um montador ou Assembler . Isso acontece pois as instruções Assembly correspondem às instruções de máquina de uma forma de 1 para 1, o que acontece no processo de montagem, é simplesmente uma pequena transformação ou tradução do código Assembly diretamente para o código de máquina.
Registradores A linguagem Assembly , como vimos, é constituída de pequenas instruções chamadas de mnemônicos. Estas instruções servem para mover dados, somar dados, subtrair, dividir, multiplicar, comparar, saltar para um ponto do programa, etc. Para armazenar valores, são necessários os registradores, que são endereços de memória encarregados de guardar ou receber dados. Os principais registradores de Assembly 16-bits são: AX, BX, CX, DX, DS, ES, SS, CS,SI, DI, BP e SP. Cada um deles (exceto DS, ES, SS, CS, SI, DI, BP e SP) podem guardar 2 bytes, sendo o primeiro byte, ou byte mais alto: AH, BH, CH e DH. E o último byte, ou byte mais baixo: AL, BL, CL, e DL.
Registrador 16-bits AX BX CX DX
Byte Alto
Byte Baixo
AH BH CH DH
AL BL CL DL
Cada registrador em Assembly tem uma função específica. Vejamos a função de cada um: AX BX CX DX DS ES SS CS SI DI BP SP
– – – – – – – – – – – –
Registrador Registrador Registrador Registrador Registrador Registrador Registrador Registrador Registrador Registrador Registrador Registrador
A cumulador B ase C ontador
de D ados de S egmento de D ados de S egmento E xtra de S egmento de Pilha/ St ack de S egmento de C ódigo de Índice da Fonte/ S ource dos Dados de Índice do D estino dos Dados de P onteiro de B ase de P onteiro da Pilha/ St ack
Instrução MOV A instrução MOV serve para MOVER dados de um lugar para o outro. Sua sintaxe é a seguinte: MOV destino,fonte Os seguintes movimentos de dados são permitidos por esta instrução: MOV MOV MOV MOV MOV MOV MOV MOV MOV
memória,acumulador acumulador,memória registrador de segmento,memória/registrador memória/registrador,registrador de segmento registrador,registrador registrador,memória memória,registrador registrador,dado memória,dado
Exemplo: MOV MOV MOV MOV MOV MOV
AX,0241h AX,AX DS,AX ES,AX DL,41h [BX],DL
;mov ;mov ;mov ;mov ;mov ;mov
registrador,dado registrador,registrador reg. De segmento,registrador reg. De segmento,registrador registrador,dado memória,registrador
Instrução LEA A Instrução LEA (Load Effective Address ) carrega o endereço do operador fonte para o destino. Sua sintaxe é a seguinte: LEA destino,fonte O uso desta instrução é similar ao uso de MOV destino, offset fonte, mas é mais simplificada.
Interrupções Interrupções são pausas geradas pelo programa para que a BIOS se dedique ao programa executando suas funções de entrada/saída. Em Assembly , o comando para se usar uma interrupção é INT. Sua sintaxe é: INT numero_da_interrupção As Interrupções tem várias funções específicas, que podem ser escolhidas através do valor contido no registrador AH.
A tabela a seguir mostra as principais funções da INT 21h do DOS: AH 00h 01h 02h 07h
09h
Descrição Termina o Programa (DOS 2.0 ou anterior) Leitura do teclado com eco na tela Escreve caracter na tela Leitura do teclado sem eco Ignora CTRL-Break Leitura do teclado sem eco Reconhece e executa CTRL-Break Escreve string na tela
0Ah*
Leitura do teclado em buffer
4Ch
Termina o Programa (mais recomendada)
08h
•
Retorno/Parâmetro AL = caracter DL = caracter AL = caracter AL = caracter DS = ponteiro para string com fim $ DS = ponteiro para buffer de leitura -
O buffer para leitura do teclado deve ter o formato:
|numero maximo de caracteres | numero de caracteres lidos | string
Exemplo: mov mov int mov int
ah,02h dl,41h 21h ah,4ch 21h
;caracter = A ;escreve caracter na tela ;finaliza o programa
Instruções ADD, SUB, MUL e DIV A instrução ADD é usada para somar dois registradores, ou um registrador e um dado. Sua sintaxe é a seguinte: ADD registrador,registrador ADD registrador,dado A instrução SUB é usada para, ao contrario da instrução ADD , subtrair dois registradores, ou um registrador e um dado. Sua sintaxe é a mesma da instrução ADD. A instrução MUL é usada para multiplicar o registrador acumulador (AX) por um outro registrador. O resultado da multiplicação é armazenado em AX, e o resto em DX. Sua sintaxe é a seguinte: MOV AX,3 MOV BX,2 MUL BX
;multiplica o valor de AX pelo valor de BX
A instrução DIV é usada para, ao contrário da instrução MUL, dividir o registrador acumulador por um outro registrador. Sua sintaxe é a seguinte: MOV AX,6 MOV BX,3 DIV BX
;divide o valor de AX pelo valor de BX
Instrução JMP A instrução JMP é usada para fazer um salto incondicional de um ponto do programa para outro, isto é, alterar a execução do programa. Sua sintaxe é a seguinte: JMP segmento JMP endereço
;no TASM, MASM ou NASM ;no DEBUG do DOS
O Comando CMP O comando CMP compara dois registradores, ou um registrador e um valor e permite fazer um salto condicional usando as seguintes instruções: JG – J ump if Greater JGE – J ump if Greater or Equal JNG – J ump if Not Greater JNGE – J ump if Not Greater or Equal JE – J ump if Equal JZ – J ump if Zero JNE – J ump if Not Equal JNZ – J ump if Not Zero JL – J ump if Lower JLE – J ump if Lower or Equal JNL – J ump if Not Lower JNLE – J ump if Not Lower or Equal Exemplo: MOV AX,0005h MOV BX,0000h CMP AX,BX ;compara AX com BX JGE 0100 ;salta para o endereço 0100 se maior ou igual --------------------------------------------------------------MOV AH,01h INT 21h CMP AL,2 ;compara AL com 2 JE 0104 ;salta para o endereço 0104 se igual
A Pilha, o PUSH e o POP A Pilha de Dados é uma estrutura muito importante em pois ela nos permite armazenar inúmeros dados de forma eficiente. Podemos imaginar a Pilha como uma pilha de primeiro a ser colocado, é o último a ser tirado, senão caem. A instrução PUSH armazena um WORD (2 bytes ou 16-bits) Sua sintaxe é a seguinte:
assembly, simples e pratos, o os pratos na Pilha.
PUSH registrador/word A instrução POP retira um WORD da Pilha e o armazena em um registrador ou em outro WORD. Sua sintaxe é a seguinte: POP registrador/word Exemplos: MOV AH,01h INT 21h MOV AH,00h PUSH AX ADD CX,1 CMP CX,5 JL 0100 POP AX MOV AH,02h INT 21h SUB CX,1 CMP CX,0 JG 0114
;zera-se o valor de AH pois AX contém AH e queremos apenas o valor de AL
;0100 é o endereço do início do programa no DEBUG do DOS
;a cada linha o endereço aumenta em 2
MOV AH,4Ch INT 21h
O DEBUG do DOS O DEBUG é uma ferramenta interessante do DOS pois ele apresenta um Assembler , isto é, um montador sequencial de instruções Assembly . Para se iniciar o Assembler do DEBUG , a linha de comando é: C:\>debug -A 0CFF:0100 Assim que iniciado o Assembler , basta digitar as instruções. Para terminar de editar o código, deve-se apertar ENTER duas vezes. Para executar o código, deve-se digitar –G. Para salvar seu programa em formato .COM, deve-se digitar –W. E, para sair do debug, deve-se digitar –Q.
Primeiro Programa O nosso primeiro programa no DEBUG deverá pedir o usuário para apertar uma tecla sem escrevê-la na tela. O programa deverá então checar se o usuário apertou a tecla ENTER. Se não, ele deve escrever a letra A na tela. Se sim, deve terminar o programa sem escrever nada. Tente fazer este programa. A resposta está no final desta apostila.
A Estrutura de um programa .EXE A estrutura de um programa .EXE é diferente da estrutura de um programa no DEBUG do MS-DOS . Isto, porque, o programa .EXE é dividido em segmentos. Para criar programas .EXE, usaremos o montador Turbo Assembler ou TASM, da Borland (vide pág. 12)
A diretiva .MODEL A diretiva .model define o modelo de memória de um programa .EXE, e deve ser incluída no início do código. Os modelos de memória são os seguintes: .model .model .model .model .model .model .model
tiny small medium compact large huge flat
;usaremos small para nossos programas
;usado em aplicativos Win32
A diretiva .STACK A diretiva .stack define o tamanho da pilha. Pode ser usada da seguinte maneira: .stack tamanho_da_pilha
A diretiva .DATA A diretiva .data é usada para declaração de variáveis. Pode ser usada da seguinte maneira: .data var1 db 10 ;db = define byte. Valor inicial = 10 var2 db ? ;Valor inicial = não definido var3 db 10 dup(‘$’) ;cria um vetor de tamanho 10 e o preenche com $ var4 dw 32767 ;dw = define word. Tamanho 2 bytes var5 dd 65536 ;dd = define double word. 4 bytes string db ‘String,’$’ ;cria uma string. Terminador $
A diretiva .CODE A diretiva .code é usada para demarcar o início do código. O código deve começar a ser executado a partir de um segmento: .code main: end main
;segmento de inicio. Pode ter qualquer nome ;termina o segmento main
Hello World O programa a seguir escreve a mensagem “Hello World” na tela e executa uma pequena pausa ao final: .model small .stack 100h .data msg db 'Hello World','$' .code main: mov ax,@data mov ds,ax mov es,ax mov ah,09 lea dx,msg int 21h mov int mov int end main
;mov dx,offset msg
ah,08h 21h ah,4ch 21h
Salve o como hello.asm e compile-o usando o TASM.
Turbo Assembler O Turbo Assembler da Borland (TASM) é um montador Assembly . Para montar programas usando esta ferramenta, deve-se usar a linha de comando do DOS. Para montar um arquivo .obj deve-se usar a seguinte linha de comando: C:\TASM\BIN>TASM hello.asm Para linkar o arquivo .obj, isto é, transforma-lo em .exe, devese usar a seguinte linha de comando: C:\TASM\BIN>TLINK hello.obj Como este processo é trabalhoso, é mais fácil usar um arquivo de Script do DOS, um arquivo .bat como este: @echo off set program=hello cls echo --------------------------echo Backup... copy /v %program%.asm /a %program%.bak /a echo --------------------------..\..\bin\TASM %program%.asm
echo --------------------------..\..\bin\TLINK %program%.obj echo --------------------------pause cls %program%.exe exit O Script acima faz uma cópia de segurança do arquivo .asm, monta-o usando o TASM, linka-o usando o TLINK e em seguida executa-o, facilitando o uso das linhas de comando.
Apêndice: Primeiro Programa O código do Primeiro Programa é o descrito abaixo: 0D03:0100 0D03:0102 0D03:0104 0D03:0106 0D03:0108 0D03:010A 0D03:010C 0D03:010E 0D03:0110 0D03:0112 0D03:0114 0D03:0116
mov int cmp jne je mov mov int jmp mov int
ah,08 21 al,0d 010A 0112 ah,02 dl,41 21 0100 ah,00h 21