Buscar

Assembly intermediário: Operações aritméticas e lógicas:Ênfase em memória

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 13 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 13 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 13 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Assembly intermediário: 
 operações aritméticas e 
lógicas:
 Ênfase em memória
Autor: Sergio Souza Novak
Estudante de Ciência da Computação UNIOESTE 
data do lançamento:11/05/2016
Este E-BOOK não será vendido.
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
“Atenção, este livro se trata de anotações minhas, de um aluno, numa aula de Assembly. 
Faça bom uso dele e seja tolerante, assim como você, estou aprendendo essa 
linguagem, parceiro, RAAAAM, kkk. E as vezes aprendo por tentativa e erro.
Lembre-se: você não pagou por esse livro.
Estamos quites ?
Então vamos lá:
Prazer, meu nome é Sergio.
O motivo de eu escrever isso é que não achei nada na internet a respeito disso que vos 
escrevo, então É MUITO BOM VOCÊ JÁ TER LIDO ARTIGOS BÁSICOS NA WEB.
Você deve fazer essas “coisas” aqui descritas no LINUX. Eu não gosto de Linux, mas é o 
jeito. E mais uma coisa: onde estiver elf64 se você usa arquitetura _x86, isto é 32bits, 
mude para elf32 e também não use registradores de ordem r_ _ (RAX,EAX,RBX...chamo 
de “r” alguma coisa), pois os “r-alguma-coisa” são compatíveis apenas com máquinas 
_x64. Caso use _x64 é ótimo você usar esses r-alguma-coisa.
O montador que eu utilizo é o NASM e para debuggar uso o GDB.
Instale no LINUX o GDB e o NASM.
Dos exemplos a seguir, salve no bloco de notas na extensão (*.asm), para mais fácil 
compreensão, aconselho que instale a sintaxe highlight que te ajuda a programar, 
sublinhando as palavras reservadas à linguagem.
Também uso a SINTAXE INTEL para assembly
hey-oh-lets-go”
Sergio Souza Novak,
autor.
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
Operações aritméticas e lógicas
Operações ARITMÉTICAS
Operações aritmética são operações do tipo adição e subtração em ponto flutuante. 
Em Assembly usamos as operações ADD e SUBB que correspondem a adição e subtração, 
respectivamente.
Temos que a operação ADD e SUBB de sintaxe:
ADD <registrador_de_destino> <valor_a_ser_adicionado>
SUBB<<registrador_de_destino> <valor_a_ser_subtraído>
Realiza a soma: 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
registrador_de_destino+registrador_de_origem 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Realiza a subtração:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
registrador_de_destino-registrador_de_origem 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
destruíndo o valor inicial de registrador_de_destino. Algo bem parecido do que se tem em C:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
registrador_de_destino=registrador_de_destino + registrador_de_origem 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
registrador_de_destino=registrador_de_destino - registrador_de_origem 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Executando o algoritmo:
section .text 
 global _start 
_start: 
 mov eax, 10 
 mov ebx, 20 
 mov ecx, 30 
 mov edx, 0xfffffffe 
add1:
 add ebx, eax 
add2:
 add edx, eax 
subb1:
 sub ecx, eax 
subb2: 
sub eax, ecx 
fim: 
 mov rax, 1 
 mov rbx, 0 
 int 0x80
Montando e lincando depois iniciando no gdb, algo do tipo:
alunos@CCSC-CC-LCT-32:~/Área de Trabalho$ nasm -f elf64 nome_do_arquivo.asm 
alunos@CCSC-CC-LCT-32:~/Área de Trabalho$ ld nome_do_arquivo.asm .o -o 
nome_do_arquivo.asm .x 
alunos@CCSC-CC-LCT-32:~/Área de Trabalho$ gdb nome_do_arquivo.asm .x 
Podemos iniciar os breakpoints declarados no corpo do código(obs: se a máquina for de 32bits 
substituir elf64 por elf32 e não usar registradores de ordem r_ _ , por exemplo RAX,RBX... típicos 
de arquitetura x_64):
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
(gdb) b add1 
Ponto de parada 1 at 0x400094 
(gdb) b add2 
Ponto de parada 2 at 0x400096 
(gdb) b subb1 
Ponto de parada 3 at 0x400098 
(gdb) b subb2 
Ponto de parada 4 at 0x40009a 
(gdb) b fim 
Ponto de parada 5 at 0x40009c 
(gdb) r
Breakpoint 1, 0x0000000000400096 in add1 ()
(gdb) p/d $eax 
$1 = 10 
(gdb) p/d $ebx 
$2 = 20 
(gdb) p/d $ecx 
$3 = 30 
(gdb) p/d $edx 
$4 = -2 
(gdb) p/x $edx 
$5 = 0xfffffffe
(gdb) c
Continuando. 
Breakpoint 2, 0x0000000000400096 in add2 () 
(gdb) p/d $ebx 
$8 = 30 
(gdb) c 
Continuando. 
Breakpoint 3, 0x0000000000400098 in subb1 () 
(gdb) p/d $edx 
$9 = 8 
(gdb) c 
Continuando. 
Breakpoint 4, 0x000000000040009a in subb2 () 
(gdb) p/d $ecx 
$10 = 20 
(gdb) c 
Continuando. 
 
Breakpoint 5, 0x000000000040009c in fim () 
(gdb) p/d $eax 
$11 = -10 
as somas e subtrações foram feitas corretamente. Vamos interpretar:
Breakpoint 1, 0x0000000000400096 in add1 ()
 O breakpoint 1 é feito antes do trecho de código que chamamos de add1, 
Depois através do comando posterior, podemos obter o resultado da série de comandos MOV. Que 
foi, realmente, bem sucedida.
Observamos que todas as operações foram devidamente satisfeitas, nada foi além do esperado, as 
operações de soma e subtração foram satisfeitas.
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
Estudando overflow e outras operações
no código exemplo 2:
section .text 
 global _start 
_start: 
 mov ax, 0x7fff ; 32767 
 mov bx, 0xffff ; 65535 
overflow: 
 add ax, 1 ; -32768 
carry: 
 add bx, 1 ; 0 
fim: 
 mov rax, 1 
 mov rbx, 0 
 int 80h
na linha que contém o MOV do valor 0x7fff em hexadecimal, temos que é um valor que quase 
ultrapassa o máximo escrito em 2 bytes. Já o número da linha seguinte é 0xffff é o maior 
representável em 2bytes.
O que pode ser testado no gdb:
(gdb) b overflow 
Ponto de parada 1 at 0x400088 
(gdb) b carry 
Ponto de parada 2 at 0x40008c 
(gdb) b fim 
Ponto de parada 3 at 0x400090 
(gdb) r 
(gdb) p/x $ax 
$1 = 0x7fff 
(gdb) p/x $bx 
$2 = 0xffff 
Os imediatos realmente foram bem movidos aos respectivos registradores.
Continuando a execução:
(gdb) c 
Continuando. 
Breakpoint 2, 0x000000000040008c in carry () 
Nesse breakpoint a instrução:
 add ax, 1 
Foi executada. Logo, podemos estudar o que houve nessa execução.
Para ter sido bem sucedida o registrador ax deve ter o conteúdo de 32768 que é 32767+1. Vamos 
assim verificar:
(gdb) p/d $ax 
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
$4 = -32768 
(gdb) p/x $ax 
$3 = 0x8000 
Observa-se que NÃO É O VALOR ESPERADO, não é de se surpreender, uma vez que o registrador 
AX é de 2bytes e o valor que se quer representar se utiliza de complemento de dois. Essa situação é 
típica de Overflow.
Existe um comando para ver se ocorreu essa situação, se trata do registrador eflags, que guarda uma 
constante referente a última operação.
(gdb) info registers eflags 
eflags 0xa96 [ PF AF SF IF OF ] 
A flag OF indica que ocorreu overflow na última operação.
Estudo das flags no registrador eflags
No terminal existe um comando quer mostra o que está acontecendo em todos os registradores, esse 
comando é:
info registers
E dá como resposta, por exemplo, isso:
rax 0x8000 32768 
rbx 0xffff 65535 
rcx 0x0 0 
rdx 0x0 0 
rsi 0x0 0 
rdi0x0 0 
rbp 0x0 0x0 
rsp 0x7fffffffe0600x7fffffffe060 
r8 0x0 0 
r9 0x0 0 
r10 0x0 0 
r11 0x0 0 
r12 0x0 0 
r13 0x0 0 
r14 0x0 0 
r15 0x0 0 
rip 0x40008c 0x40008c <carry> 
eflags 0xa96 [ PF AF SF IF OF ] 
cs 0x33 51 
ss 0x2b 43 
ds 0x0 0 
es 0x0 0 
fs 0x0 0 
i r é a abreviação de info registers. Ou seja, podemos abreviar o comando fazendo:
(gdb) i r 
que dá a mesma saída.
Para selecionar apenas um registrador usa-se a sintaxe:
i r <nome_do_registrador>
O <nome_do_registrador> é um dos nomes citados no escopo info registers.
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
Para análise de overflow analisaremos primeiramente o registrador eflags que guarda constantes a 
respeito da última operação:
(gdb) i r eflags 
eflags 0xa96 [ PF AF SF IF OF ] 
 Este comando dá expressões chamadas de flags, que mostram características a respeito da última 
operação. Por exemplo, a flag IF. 
As flags mais conhecidas:
IF(Flag de interrupção) : se esta flag estiver presente significa 
que o sistema teve que criticamente parar por algum motivo devido 
a privilágio de sistema. Essa flag não será estudada.
OF (Flag de overflow): essa flag presente indica que a última 
operação ocorreu overflow.
AF (Flag de ajuste de carry): essa flag presente indica que a 
última operação ocorreu um carry que “espirrou” fora dos 4 bits 
menos significativos.
SF (Flag de sinal): essa flag indica que na última operação foi 
negativa e em complemento de 2.
PF (Flag de Paridade): essa flag indica que a última operação o 
resultado retornado foi par.
 As flags só são acionadas por operações lógicas ou aritméticas, ou seja a operação MOV não é 
considerada pelo registrador eflags pois MOV é uma instrução de referência.
Conclusão
Concluímos que nas operações aritméticas deve-se cuidar com operações de soma e subtração, uma 
vez que estas são feitas bit-a-bit e o Assembly as usa indiscriminadamente.
Resolvendo o problema
Podemos resolver o problema, por exemplo, no código:
section .text 
 global _start 
_start: 
c1: 
 mov eax, -1 
 add eax, 2 
c2: 
 adc ebx, eax 
b1: 
 mov ecx, 2 
 sub ecx, 3 
b2: 
 sbb edx, ecx 
fim: 
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
 mov rax, 1 
 mov rbx, 0 
 int 0x80
que no terminal, montando e linkando depois iniciando no gdb, por exemplo, se o nome do arquivo 
for nome_do_arquivo:
alunos@CCSC-CC-LCT-32:~/Área de Trabalho$ nasm -f elf64 nome_do_arquivo.asm 
alunos@CCSC-CC-LCT-32:~/Área de Trabalho$ ld nome_do_arquivo.asm .o -o 
nome_do_arquivo.asm .x 
alunos@CCSC-CC-LCT-32:~/Área de Trabalho$ gdb nome_do_arquivo.asm .x 
e no gdb, iniciando os breakpoints nos lugares especificados no corpo do código temos a saída
(gdb) b c1 
Ponto de parada 1 at 0x400080 
(gdb) b c2 
Ponto de parada 2 at 0x400088 
(gdb) b b1 
Ponto de parada 3 at 0x40008a 
(gdb) b b2 
Ponto de parada 4 at 0x400092 
(gdb) b fim 
Ponto de parada 5 at 0x400094 
(gdb) r 
Starting program: /home/alunos/Área de Trabalho/a05e03.x 
warning: no loadable sections found in added symbol-file system-supplied DSO at 
0x7ffff7ffd000 
Breakpoint 1, 0x0000000000400080 in c1 () 
(gdb) c 
Continuando. 
Breakpoint 2, 0x0000000000400088 in c2 () 
(gdb) p/c $eax 
$1 = 1 '\001' 
(gdb) p/d $eax 
$2 = 1 
(gdb) c 
Continuando. 
Breakpoint 3, 0x000000000040008a in b1 () 
(gdb) p/d $eax 
$3 = 1 
(gdb) p/d $ebx 
$4 = 2 
(gdb) c 
Continuando. 
Breakpoint 4, 0x0000000000400092 in b2 () 
(gdb) p/d $ecx 
$5 = -1 
(gdb) p/x $ecx 
$6 = 0xffffffff 
(gdb) i r eflags 
eflags 0x297 [ CF PF AF SF IF ] 
(gdb) c 
Continuando. 
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
Breakpoint 5, 0x0000000000400094 in fim () 
(gdb) p/x $edx 
$7 = 0x0 
(gdb) p/d $edx 
$8 = 0 
(gdb) i r eflags 
eflags 0x257 [ CF PF AF ZF IF ] 
As operações com carry foram devidamente satisfeitas, solucionando o problema e eliminando o 
overflow, resultando em apenas uma flag de carry.
Adc pega a carry anterior e adiciona.
Adc pega o dígito que “espirra”.
Se adc não tiver carry é igual a add, caso contrário, atua no carry.
Operações LÓGICAS
Estudaremos a seguir, operações do tipo LÓGICAS, as conhecidas operações 
AND,OR,XOR,NOT,...etc. 
Para isso, usaremos o seguinte código:
section .data
 v1: dw 0xfffb ; 1111.1111 1111.1011
 v2: dw 0xaaaa ; 1010.1010 1010.1010
section .bss
 v1orv2: resw 1
 v1andv2: resw 1
 v1xorv2: resw 1
section .text
 global _start
_start:
 mov ax, [v1]
 mov bx, [v2]
 mov cx, [v2]
btesteum:
 ; or reg x reg
 or cx, ax
btestedois:
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
 ; or mem x reg
 mov [v1orv2], ax
 or [v1orv2], bx
btestetres:
 ; or reg, imm
 or bx, 0x00ff
btestequatro:
 ; and
 mov ax, [v1]
 mov bx, [v2]
 mov cx, [v2]
btestecinco:
 ; and reg x reg
 and cx, ax
btesteseis:
 ; and mem x reg
 mov [v1andv2], ax
 and [v1andv2], bx
btestesete:
 ; and reg, imm
 and bx, 0x00ff
btesteoito:
xorlabel:
 ; xor
 mov ax, [v1]
 mov bx, [v2]
 mov cx, [v2] 
btestenove:
 ; xor reg x reg
 xor cx, ax
 ; xor mem x reg
 mov [v1xorv2], ax
 xor [v1xorv2], bx
 ; xor reg, imm
 xor bx, 0x00ff
fim:
 mov rax, 1 
 mov rbx, 0
 int 0x80
montando e linkando depois, no gdb, por exemplo, o nome do meu arquivo é “a05e04.asm”:
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
alunos@CCSC-CC-LCT-32:~/Área de Trabalho$ nasm -f elf64 a05e04.asm
alunos@CCSC-CC-LCT-32:~/Área de Trabalho$ ld a05e03.o -o a05e03.x
alunos@CCSC-CC-LCT-32:~/Área de Trabalho$ gdb a05e04.x
No gdb, iniciando os breakpoints:
(gdb) b btesteum
Ponto de parada 1 at 0x4000c8
(gdb) b btestedois
Ponto de parada 2 at 0x4000cb
(gdb) b btestetres
Ponto de parada 3 at 0x4000db
(gdb) b btestequatro
Ponto de parada 4 at 0x4000e0
(gdb) b btestecinco
Ponto de parada 5 at 0x4000f8
(gdb) b btesteseis
Ponto de parada 6 at 0x4000fb
(gdb) b btestesete
Ponto de parada 7 at 0x40010b
(gdb) b btesteoito
Ponto de parada 8 at 0x400110
(gdb) b btestenove
Ponto de parada 9 at 0x400128
(gdb) b fim
Ponto de parada 10 at 0x400140
A partir disso, você pode testar o conteúdo dos registradores com o comando:
Se quiser o conteúdo em binário:
p/t $<nome_do_registrador>
Se quiser o conteúdo em hexadecimal:
p/x $<nome_do_registrador>
Se quiser o conteúdo em decimal:
p/d $<nome_do_registrador>
Se quiser o conteúdo em caracteres ASCII:
p/c $<nome_do_registrador>
para iniciar a execução use run:
(gdb) r
para saltar em cada breakpoint use continue:
(gdb) c
Exercício
1.Teste em binário as operações lógicas em cada registrador.
2.Qual instrução é unária e qual instrução é binaria neste código?
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com
AUTOR: SERGIO SOUZA NOVAK
e-mail:serginhosnovak@hotmail.com

Outros materiais