06 - Condicionais e funções
Na aula de hoje vamos revisar e praticar os conceitos de funções e condicionais em Assembly. Teremos exercícios simples de cada assunto e no fim alguns exercícios para entrega que juntam coisas diferentes.
Funções e aritmética com LEA
Todos os exercícios da revisão serão feitos com o arquivo exemplo1
(compilado a partir de exemplo1.c
). Vamos examinar tanto a função main
quanto a função exemplo1
.
Compile com:
Chamadas de funções
As chamadas de função são feitas usando a seguinte ordem para os argumentos inteiros:
%rdi
%rsi
%rdx
%rcx
%r8
%r9
Esta ordem nunca muda. Veja abaixo um exemplo de chamada de função tirado do main
de exemplo1
.
0x01163 <+8>: mov $0x6,%r9d
0x01169 <+14>: mov $0x5,%r8d
0x0116f <+20>: mov $0x4,%ecx
0x01174 <+25>: mov $0x3,%edx
0x01179 <+30>: mov $0x2,%esi
0x0117e <+35>: mov $0x1,%edi
0x01183 <+40>: call 0x1149 <exemplo1>
0x01188 <+45>: lea 0xa(%rax),%esi
Pergunta 1
Answer
A ordem dos parâmetros segue é sempre a mesma vista na aula 04. Mesmo que as instruções estejam em ordem diferente, %edi
(ou uma de suas partes) é sempre o primeiro parâmetro.
Exercise 2
Answer
exemplo1(1, 2, 3, 4, 5, 6)
Vamos agora analisar o código de exemplo1
:
Dump of assembler code for function exemplo1:
0x01149 <+0>: endbr64
0x0114d <+4>: add %esi,%edi
0x0114f <+6>: add %edx,%edi
0x01151 <+8>: add %ecx,%edi
0x01153 <+10>: add %r8d,%edi
0x01156 <+13>: lea (%rdi,%r9,1),%eax
0x0115a <+17>: ret
Exercise 3
Answer
Pelos registradores utilizados, percebemos que a função tem seis parâmetros, todos int
.
O retorno também é int
.
Exercise 4
Answer
int exemplo1(int a, int b, int c, int d, int e, int f);
Exercise 5
Answer
Ela soma os primeiros 5 argumentos: a + b + c + e
.
Vemos na linha exemplo1+13
que colocamos um valor no registrador %eax
e depois finalizamos a função usando ret
. Este é o segundo ponto que nunca muda: o valor de retorno de toda função é colocado no registrador %rax
(ou uma de suas partes menores). Neste exemplo, a instrução usada foi o LEA
que relembraremos na seção a seguir.
Operações aritméticas usando LEA
Se usada de maneira literal, a instrução LEA (Load Effective Address) serve para calcular o endereço de uma variável local e é equivalente ao operador &
em C. Porém, ela é frequentemente "abusada" para fazer aritmética. Um ponto importante quando usamos LEA
é que todos os operandos são registradores de 64
bits.
Regra geral 1
- Se
LEA
for usada com o registrador%rsp
então ela sempre representa o operador&
- Se os registradores envolvidos foram usados como números inteiros em instruções anteriores, então ela representa uma conta com os valores dos registradores.
Vejamos o exemplo da função exemplo1
acima:
No exemplo acima LEA
é usada para fazer aritmética. Sabemos disso pois, na chamada traduzida na parte anterior, elas recebem números inteiros (%r9d = 6
e %edi = 1
mais o resultado de sucessivas somas). Seu primeiro argumento segue a seguinte lógica
C
é uma constante%R1
é um registrador%R2
é um registrador (pode ser igual a%R1
)S
é1, 2, 4
ou8
(todos os tamanhos possíveis de registradores inteiros)
A operação acima calcula C + %R1 + (%R2 * S)
. A operação LEA
nunca acessa a memória, apenas move o resultado deste cálculo para o registrador destino. Qualquer outra operação que use a sintaxe acima está fazendo um acesso a memória. LEA
é a única exceção!
Exercise 6
Answer
Supondo que aux = a+b+c+d+e
já foi calculado com o uso das instruções ADD
, então o LEA
calcula aux + f*1
.
Exercise 7
Answer
Confira no arquivo exemplo1.c
Retorno de funções
Vamos terminar nossa revisão analisando novamente a chamada de exemplo1
no main
:
0x01163 <+8>: mov $0x6,%r9d
0x01169 <+14>: mov $0x5,%r8d
0x0116f <+20>: mov $0x4,%ecx
0x01174 <+25>: mov $0x3,%edx
0x01179 <+30>: mov $0x2,%esi
0x0117e <+35>: mov $0x1,%edi
0x01183 <+40>: call 0x1149 <exemplo1>
0x01188 <+45>: lea 0xa(%rax),%esi
Anteriormente já vimos que o call
e os mov
s acima fazem a chamada exemplo1(1,2,3,4,5,6)
em C.
A linha de baixo realiza uma operação aritmética com %rax
.
Exercise 8
Answer
int esi = exemplo1(1, 2, 3, 4, 5, 6) + 10;
Exercícios combinados
Warning
Todos os exercícios desta seção são para entrega. Vocês podem se conversar para fazê-los, mas cada um deve criar sua própria solução do zero. Todos os exercícios já estão disponíveis no seu repositório de entregas da disciplina em atv/04-condicionais-funcoes
. Leia o README
dentro da pasta para mais informações.
Função ex1
: Aritmética e Expressões booleanas.
Dump of assembler code for function ex1:
0x000 <+0>: endbr64
0x004 <+4>: lea (%rdi,%rsi,1),%rax
0x008 <+8>: lea (%rax,%rdx,4),%rcx
0x00c <+12>: imul %rdi,%rdi
0x010 <+16>: lea (%rdi,%rsi,2),%rax
0x014 <+20>: add %rax,%rdx
0x017 <+23>: cmp %rdx,%rcx
0x01a <+26>: setge %al
0x01d <+29>: movzbl %al,%eax
0x020 <+32>: ret
Exercise 9
Exercise 10
Exercise 11
Exercise 12
Exercise 13
Example
Usando as perguntas acima preencha o arquivo de solução no repositório e execute os testes.
Função ex2
: Chamadas de funções e Condicionais.
Quando analisar o código do ex2 no gdb, utilize o arquivo ex2_ref
para visualizar corretamente as chamadas de funções. Seria uma boa também consultar as relocation entries no terminal com objdump -r ex2.o
.
Dump of assembler code for function ex2:
0x01132 <+0>: endbr64
0x01136 <+4>: push %rbx
0x01137 <+5>: mov %rdi,%rbx
0x0113a <+8>: mov %rsi,%rdi
0x0113d <+11>: call 0x1129 <vezes2>
0x01142 <+16>: cmp %rbx,%rax
0x01145 <+19>: jle 0x114a <ex2+24>
0x01147 <+21>: add %rbx,%rbx
0x0114a <+24>: add %rbx,%rax
0x0114d <+27>: pop %rbx
0x0114e <+28>: ret
Exercise 14
Vamos começar trabalhando na linha ex2+11
, na instrução call vezes2
. A chamada necessita usar o registrador %rdi
, mas ele contém o primeiro argumento de ex2
.
Exercise 15
Exercise 16
Exercise 17
Você deve ter notado as instruções push/pop %rbx
no começo/fim da função. Toda função pode usar os registradores de argumentos (vistos na parte 1) e o de valor de retorno como quiserem. Se precisarem mexer nos outros registradores a prática é salvá-los na pilha no começo da função e restaurá-los no fim. Assim não importa o que a função faça, para a função chamadora é como se não houvesse havido nenhuma modificação nos outros registradores.
Vamos agora olhar a condicional na linha ex2+16
.
Exercise 18
Exercise 19
Exercise 20
Example
Usando as perguntas acima preencha o arquivo de solução no repositório e execute os testes.
Função ex3
: Ponteiros e Expressões booleanas.
Dump of assembler code for function ex3:
0x000 <+0>: endbr64
0x004 <+4>: cmp %rsi,%rdi
0x007 <+7>: setl %al
0x00a <+10>: movzbl %al,%eax
0x00d <+13>: mov %eax,(%rdx)
0x00f <+15>: sete %al
0x012 <+18>: movzbl %al,%eax
0x015 <+21>: mov %eax,(%rcx)
0x017 <+23>: setg %al
0x01a <+26>: movzbl %al,%eax
0x01d <+29>: mov %eax,(%r8)
0x020 <+32>: ret
Exercise 21
Exercise 22
Exercise 23
Exercise 24
Example
Usando as perguntas acima preencha o arquivo de solução no repositório e execute os testes.
Função ex4
: Ponteiros e Expressões booleanas.
Dump of assembler code for function ex4:
0x00a <+0>: endbr64
0x00e <+4>: cmp $0x11,%di
0x012 <+8>: jle 0x21 <ex4+23>
0x014 <+10>: sub $0x41,%esi
0x017 <+13>: cmp $0x1,%sil
0x01b <+17>: ja 0x29 <ex4+31>
0x01d <+19>: lea -0x11(%rdi),%eax
0x020 <+22>: ret
0x021 <+23>: mov $0x12,%eax
0x026 <+28>: sub %edi,%eax
0x028 <+30>: ret
0x029 <+31>: mov $0xffffffff,%eax
0x02e <+36>: ret
Exercise 25
Exercise 26
Exercise 27
Exercise 28
Example
Usando as perguntas acima preencha o arquivo de solução no repositório e execute os testes.