Programação ao nível da máquina

Propaganda
Programação ao nível da máquina
Instruções de controlo
Variáveis
Vectores
Instruções de controlo
Saltos (jumps): alteram o valor do EIP - Instruction
Pointer (ou Program Counter)
Incondicionais
Exemplo: jmp endereço
eip endereço
a próxima instrução executada é a que se encontra no
endereço indicado
Condicionais
Primeiro testam códigos de condição (flags).
Exemplos:
jz endereço só salta se a flag de Zero estiver a 1
jnz endereço só salta se a flag de Zero estiver a 0
Outras instruções testam outras flags ou conjuntos de
flags.
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
167
Saltos condicionais (com uma flag)
Os que testam directamente uma flag
Salta se:
Carry
Overflow
Signal
Zero
CF=1
CF=0
OF=1
OF=0
SF=1
SF=0
ZF=1
ZF=0
JC – Jump if Carry
JNC – Jump if Not Carry
JO – Jump if Overflow
JNO – Jump if Not Overflow
JS – Jump if Sign
JNS – Jump if Not Sign
JZ – Jump if Zero
JNZ – Jump if Not Zero
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
168
Saltos condicionais (inteiros s/sinal)
As relações entre inteiros sem sinal, são dadas, após
cmp (ou sub) pelas flags:
após sub X,Y ou cmp X,Y
se X<Y CF=1 (borrow)
se X=Y ZF=1
se X>Y CF=0 e ZF=0
Saltos condicionados por estas flags:
JB
– Jump if Below (=JC)
JE
– Jump if Equal (=JZ)
JA
– Jump if Above (CF=0 e ZF=0)
JBE
– Jump if Below or Equal (CF=1 ou ZF=1)
JAE
– Jump if Above or Equal (=JNC)
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
169
Saltos condicionais (aliases)
Mais mnemónicas para as mesmas instruções:
JNBE = JA
JNB = JAE = JNC
JNA = JBE
JNAE = JB = JC
JNE = JNZ
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
170
Comparar números com sinal
Sem sinal
1111 1111 = 25510
0000 0000 = 010
Com sinal
1111 1111 = -110
0000 0000 = 010
Qual é maior?
255 > 0
Qual é maior?
-1 < 0
Flag a testar?
Carry (CF), usando
sub/cmp
Flag a testar?
necessitamos de testar
flags diferentes
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
171
Exemplos de comparações
Usando cmp/sub para X>Y:
X
Y
X-Y
OF
SF
0111 (7)
0001 (1)
0110 (6)
0
0
0001 (1)
1110 (-2)
0011 (3)
0
0
0001 (1)
1001 (-7)
1000 (-8?)
1
1
1111 (-1)
1001 (-7)
0110 (6)
0
0
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
172
Exemplos de comparações
Usando cmp/sub para X<Y:
X
Y
X-Y
OF
SF
0001 (1)
0111 (7)
1010 (-6)
0
1
1000 (-8)
0001 (1)
0111 (3?)
1
0
1001 (-7)
0001 (1)
1000 (-8)
0
1
1001 (-7)
1111 (-1)
1010 (-6)
0
1
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
173
Conclusão
Comparação usando cmp/sub entre números com
sinal:
Quando X-Y>=0 (SF=0) então X>=Y, excepto se
houver Overflow (OF=1)
Após sub X,Y ou cmp X,Y
Se X > Y
Greater than:
Se X >= Y
Greater or Equal:
Se X < Y
Less than:
Se X <= Y
Less or Equal:
SF = OF and ZF = 0
SF = OF
SF ≠ OF and ZF = 0
SF ≠ OF or ZF = 1
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
174
Saltos condicionais (inteiros c/sinal)
Saltos condicionais para as relações entre inteiros
com sinal:
JG
– Jump if greater than (=JNLE)
JGE
– Jump if greater or equal (=JNL)
JL
– Jump if less than (=JNGE)
JLE
– Jump if less or equal (=JNG)
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
175
Comparando números (sub/cmp)
Sem sinal
1111 1111 = 25510
0000 0000 = 010
Com sinal
1111 1111 = -110
0000 0000 = 010
Qual é maior?
255 > 0
Qual é maior?
-1 < 0
Necessitamos de instruções que comparem flags
diferentes. Exemplos:
Flag a testar:
Carry (CF)
ja /jb / etc
Flags a testar:
Sign (SF) e Overflow (OF)
jg / jl / etc
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
176
Etiquetas (labels)
Em vez de usar endereços, no assembly etiqueta-se
as posições de memória
Exemplo:
ciclo: add eax, ebx
jmp ciclo
ciclo representa o endereço de memória onde
fica a instrução ‘add eax, ebx’
Usa-te também para etiquetar posições de
memória que contém dados: variáveis
Exemplo, carregar para eax o conteúdo de Var
mov eax, [Var]
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
177
Exemplo: if
Como executar código diferente dependendo de
uma condição?
condição estado das flags
salto condicional (jxx)
if (condicao)
codigo_do_then;
else
codigo_do_else;
; código da condição de modo
; a que altere as flags
; (exemplo cmp eax, 5)
jxx bloco_else
; codigo_do_then
jmp fim_if
bloco_else:
; codigo_do_else
fim_if:
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
178
Exemplo: if
Exemplo
if (x < 5)
codigo_do_then;
else
codigo_do_else;
mov eax, [x]
cmp eax, 5
jge bloco_else
; codigo_do_then (eax < 5)
jmp fim_if
bloco_else:
; codigo_do_else (eax ≥ 5)
fim_if:
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
179
Exemplo: while
Ciclo com teste "à cabeça"
while (condicao)
codigo_do_ciclo;
inicio_while:
; código da condição de modo
; a que altere as flags
; (exemplo cmp ax, 5)
jxx fim_while
; codigo_do_ciclo
jmp inicio_while
fim_while:
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
180
Exemplo: while
Exemplo
while (x < 5)
codigo_do_ciclo;
inicio_while:
mov eax, [x]
cmp eax, 5
jge fim_while
; codigo_do_ciclo
jmp inicio_while
fim_while:
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
181
Exemplo: do-while
Ciclo com teste "no fim"
do
codigo_do_ciclo;
while (condicao);
inicio_do:
; codigo_do_ciclo
; código da condição de modo
; a que altere as flags
; (exemplo cmp ax, 5)
jxx inicio_do
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
182
Exemplo: do-while
Exemplo
do
codigo_do_ciclo;
while (x < 5);
inicio_do:
; codigo_do_ciclo
mov eax, [x]
cmp eax, 5
jl inicio_do
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
183
Exemplo: for
Ciclo com base num contador
for ( i=n; i>0; i-- )
codigo_do_ciclo;
mov ecx, [n]
inicio_for:
cmp ecx, 0
jle fim_for
; codigo_do_ciclo
dec ecx
jmp inicio_for
fim_for:
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
184
LOOP
Salto com base num contador, para ciclos que
executam pelo menos uma vez
Equivale a ‘dec cx’ seguido de ‘jnz’
Usa implicitamente o registo CX (16bits)
for ( i=n; i>0; i-- )
codigo_do_ciclo;
mov cx, [n]
inicio_for:
; codigo_do_ciclo
loop inicio_for
Nota: tem de n > 0!
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
185
Declarar variáveis
Declarar dados inicializados
DB – 8 bits
DW – 16 bits
DD – 32 bits
DQ – constante virgula flutuante em 64 bits
DT – constante virgula flutuante em 80 bits
Exemplo:
Var: dd 20 ; um inteiro a 32 bits com o valor 20
Reservar espaço para dados não inicializados
RESB, RESW, RESD, RESQ e REST
Exemplo :
Var: resd 1 ; espaço para 1 inteiro a 32 bits
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
186
Declarar vectores
Um vector é um conjunto contíguo de dados do
mesmo tipo
Exemplos:
vector1: dw 1,2,3,4,5
vector2: resb 20
; um vector de 5 elementos de
; 16 bits
; reservar um vector de 20 bytes
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
187
Exemplo: somar elementos de um vector
Dados:
vector: dd 1, 2, 3, 4, 5, 6, 7
len:
dw 7
Código da soma
l:
mov eax, 0
mov ebx, vector
mov cx, [len]
add eax, [ebx]
add ebx, 4
loop l
…
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
188
Endereço de um elemento de um vector
Consideremos o seguinte vector:
vector:
dd 1, 2, 3, 4, 5, 6, 7
Calcular o endereço do valor 7, considerando que
ecx contém o numero de elementos do vector
mov
mov
sub
mul
add
ebx, vector
eax, ecx
eax, 1
dword 4
ebx, eax
O IA-32 tem modos de endereçamento que facilitam
um pouco a programação
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
189
Modos de endereçamento no IA-32
Forma geral para endereçamento indirecto no IA-32:
[Rb+Ri*S+D]
D: Constante “deslocamento”
Rb: Registo Base: Qualquer dos 8 registos inteiros
Ri: Registo índice: Qualquer, excepto esp
Também é pouco provável que seja ebp
S: Escala
Casos especiais
[D]
[Rb]
[Rb+Ri]
[Rb+Ri+D]
[Rb+Ri*S]
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
190
Endereçamento baseado
O endereço efectivo é obtido somando o conteúdo
de um registo (registo base ou índice) a uma
constante
exemplo: mov eax, [ebx+8]
load-baseado eax ebx
Registo especificado na
instrução (ebx)
Memória
8
+
Endereço
efectivo
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
191
Endereçamento baseado
Conveniente para endereçar estruturas
struct my_struct { // estrutura em C
int a;
// ocupa 4 bytes
double b; // ocupa 8 bytes
char c;
// ocupa 1 byte
} s1;
+13
c, ocupa 1 byte,
Distância do início:12
+12
b, ocupa 8 bytes
distância do início: 4
Se registo base com endereço de s1:
[RegBase + 0] : campo a da estrutura
[RegBase + 4] : campo b da estrutura
[RegBase + 12]: campo c da estrutura
+4
a, ocupa 4 bytes
distância do início:0
Endereço Inicial
da variável s1
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
192
Endereçamento indexado
O endereço efectivo é obtido somando o conteúdo
de dois registos (registos base e índice).
Exemplo: mov [ebx+ecx], 5
store-im-ind
ebx ecx
5
Memória
Registo 1 (ebx)
+
Registo 2 (ecx)
Endereço
efectivo
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
193
Endereçamento indexado com escala
O endereço efectivo é obtido somando o conteúdo
de dois registos (registos base e índice).
Exemplo: mov [ebx+ecx*4], 5
store-im-scl-ind ebx ecx
4
5
Memória
Registo 2 (ecx)
x
+
Endereço
efectivo
Registo 1 (ebx)
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
194
Endereçamento indexado com escala
Conveniente para endereçar vectores
int arr[100];
…
Sabendo o endereço de arr:
Um registo pode funcionar como índice
[arr+ regInd] onde regInd toma os
valores 0, 1, 2 …
Exemplo: percorrer o vector:
mov ebx, 0
Ciclo: mov eax, [arr+ebx*4]
[arr+ebx]
inc
addebx
ebx, 4
cmp ebx, 100
400
jne Ciclo
arr[3],
+12 distância do início:12
arr[2],
+8 distância do início:8
+4
arr[1],
distância do início:4
arr[0], ocupa 4bytes
distância do início:0
Endereço Inicial
do vector arr
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
195
Aceder a vectores: os registos ESI e EDI
Registos de uso geral, normalmente utilizados para
percorrer vectores em memória
ESI - Índice de origem (Source Index)
EDI - Índice de destino (Destination Index)
32 bits
16 bits
edi
di
esi
si
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
196
Uso do registo ESI no exemplo anterior
Conveniente para endereçar vectores
int arr[100];
…
Sabendo o endereço de arr:
Um registo pode funcionar como índice
[arr+ regInd] onde regInd toma os
valores 0, 1, 2 …
Exemplo: percorrer o vector:
mov esi, 0
Ciclo: mov eax, [arr+esi*4]
inc esi
cmp esi, 100
jne Ciclo
arr[3],
+12 distância do início:12
arr[2],
+8 distância do início:8
+4
arr[1],
distância do início:4
arr[0], ocupa 4bytes
distância do início:0
Endereço Inicial
do vector arr
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
197
Endereçamento baseado+indexado
O endereço efectivo é obtido somando o conteúdo
de dois registos (registos base e índice) mais uma
constante (deslocamento)
Existe ainda a variante com escala
Exemplo: mov [ebx+esi+10], 5
store-im-bas-ind ebx esi
10
Registo 1 (ebx)
+
+
Memória
5
Endereço
efectivo
Registo 2 (esi)
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
198
Endereçamento baseado+indexado
Conveniente para endereçar um
vector de estruturas
struct my_struct {
... // struct com 16 bytes
} arr[100];
arr[99]
Suponhamos um registo base (reg1)
com o endereço inicial do vector arr
Para aceder ao elemento i carregase outro registo (reg2) com i
+48
arr[2]
+32
arr[1]
+16
[reg1 + reg2*16 + 0] : endereço de arr[i].a
arr[0]
[reg1 + reg2*16 + 4] : endereço de arr[i].b
[reg1 + reg2*16 + 12]: endereço de arr[i].c Endereço Inicial
do vector arr
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
199
Exemplos de cálculo do endereço efectivo
edx
0xf000
ecx
0x100
End. assembly
[edx+0x8]
Cálculo
0xf000 + 0x8
[edx+ecx]
0xf000 + 0x100
0xf100
[edx+ecx*4]
0xf000 + 4*0x100
0xf400
[edx*2+0x80]
2*0xf000 + 0x80
0x1e080
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
Endereço
0xf008
200
Modos de endereçamento no NASM
O NASM permite uma sintaxe mais abrangente e
portanto podemos usar posições de memória em vez
de registos e realizar operações algébricas que não
as definidas no IA-32
Exemplos:
mov eax, [vector+ecx]
eax Mem[vector+ecx]
mov eax, [vector+(ecx-1)*2]
eax Mem[vector+(ecx-1)*2]
O NASM converte estas notações para as disponíveis
no IA-32
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
201
A instrução LEA
Podemos usar a instrução lea para calcular um
endereço efectivo, por exemplo o endereço de um
elemento de um vector:
vector:
dd 1, 2, 3, 4, 5, 6, 7
Consideremos que:
ebx contém o endereço de vector
ecx contém o numero de elementos do vector
dec ecx
lea edx, [ebx+ecx*4]
Podemos ainda usar a notação mais flexível do NASM
lea edx, [vector+(ecx-1)*4]
Arquitectura de Computadores (2008/2009): Programação ao nível da máquina
202
Download