Suponha que as variáveis (int)
a, b, c e d
estão alocadas respectivamente nos registradores
eax, ebx, ecx e edx.
Como programar estruturas como:
if (a==b) c=d; d=a+c;ou
while (a<=b) {
...
a++;
}
d=a+c;
?
A forma natural de execução do programa é a sequencial, ou seja, a CPU automaticamente busca instruções na memória em endereços sequenciais. Instruções de desvio de assembly servem para "quebrar" a execução sequencial, fazendo com que, sob certas condições, deixe de valer a regra que diz que sempre a próxima instrução a ser executada é a próxima fisicamente na memória.
Existem instruções de desvio condicional e incondicional.
No Pentium os desvios são chamados jump,
em algumas outras máquinas são chamadas de branch.
Um exemplo de jump condicional é a instrução:
jle label
Observe que a condição do jump se refere ao resultado da instrução anterior. Em outras máquinas, a própria instrução de desvio contém os operandos a serem comparados. No Pentium, diversas instruções registram características de seus resultados nos flags, e os desvios condicionais operam sobre os valores dos flags. Por exemplo, podemos escrever
cmp %eax, %ebx
jle depois
Nesse caso, se o valor de ebx for menor ou igual que o de eax
(observe a "inversão" dos operandos),
o controle é desviado para o endereço indicado pelo label depois.
Para programar o if acima, poderíamos escrever:
cmpl %eax, %ebx
jne depois_if
movl %edx, %ecx
depois_if:
movl %eax, %edx
addl %ecx, %edx
atenção: Observe que a condição de desvio é a negativa da condição do if!!
Existem muitas outras instruções de desvio condicional (ver manual),
como je, jg, jge, jecxz, etc.
Um exemplo de desvio incondicional é a instrução:
jmp depois
que faz com que o controle seja desviado para o endereço indicado pelo label depois, independentemente de qualquer condição.
Para implementar uma estrutura if ... else ...
é necessário utilizar um desvio condicional e um incondicional!
Tente fazê-lo!
Para programar o while acima, poderíamos escrever:
loop: cmpl %ebx, %eax
jgt depois
...
incl %eax
jmp loop ; desvia para teste
depois: movl %eax, %edx
addl %ecx, %edx
e se for um do..while?
Nos exemplos acima, as condições eram sempre condições simples, que podiam ser testadas com uma instrução de comparação. Muitas vezes, temos expressões mais complexas, envolvendo and e or.
A maior parte das linguagens de programação atuais utilizam o que se chama de curto circuito: a avaliação de uma expressão lógica é interrompida assim que o resultado é conhecido. Por exemplo, em uma expressão com and, se o resultado da primeira parte é falso, não se avalia a segunda. Por outro lado, em um or, se o resultado da primeira parte é verdadeiro, também não se avalia a segunda.
Como exemplo, supondo mais uma vez que
as variáveis
a, b, c e d
estão alocadas nos registradores
eax, ebx, ecx e edx,
o código C:
if ((a==b)||(c<d)) {
a = c;
}
c = d;
pode ser implementado por:
cmpl %ebx, %eax
je l1
cmpl %edx, %ecx
lge l2
l1: movl %eax, %ecx
l2: movl %ecx, %edx