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 depoisNesse 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