Skip to content

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:

$ gcc -Og -Wall -std=c99 exemplo1.c -o exemplo1

Chamadas de funções

As chamadas de função são feitas usando a seguinte ordem para os argumentos inteiros:

  1. %rdi
  2. %rsi
  3. %rdx
  4. %rcx
  5. %r8
  6. %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

O valor do primeiro argumento da função é

  • 6
  • 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

A instrução call realiza chamadas de função. Traduza a chamada de função acima para C.

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

Quantos parâmetros a função acima recebe? Quais seus tipos? Ela retorna algum valor? Se sim, qual seu tipo?

Answer

Pelos registradores utilizados, percebemos que a função tem seis parâmetros, todos int. O retorno também é int.

Exercise

Declare a função acima com base na sua resposta anterior.

Answer

int exemplo1(int a, int b, int c, int d, int e, int f);

Exercise

O que faz o conjunto de instruções add nas linhas +4 até +10? Escreva uma expressão em C equivalente.

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 &
  2. 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:

    lea    (%rdi,%r9,1),%eax
   0x01156 <+13>:   lea    (%rdi,%r9,1),%eax

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(%R1, %R2, S)
  • C é uma constante
  • %R1 é um registrador
  • %R2 é um registrador (pode ser igual a %R1)
  • S é 1, 2, 4 ou 8 (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

Traduza a operação abaixo para C

   0x01156 <+13>:   lea    (%rdi,%r9,1),%eax

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

Com estas informações em mãos, traduza exemplo1 para C

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

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

Considerando que %rax armazena o valor de retorno de uma função, qual seria a tradução para C do bloco de código acima?

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

Quantos argumentos a função acima recebe? Quais seus tipos? Declare a função abaixo.

Exercise

As instruções LEA acima representam operações aritméticas ou a operação endereço de &? Como você fez esta identificação? .

Exercise

Traduza as operações das linhas ex1+0 até ex1+16 para C

Exercise

Nas linhas ex1+23 e ex1+26 é feita uma comparação. Qual e entre quais registradores? Onde é armazenado este resultado?

Exercise

O quê faz a instrução movzbl em ex1+29? Juntando com a resposta da pergunta acima, traduza as instruções ex1+23 até ex1+32 para C.

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

Quantos argumentos a função acima recebe? Quais são seus tipos? Declare-a abaixo.

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

Em qual registrador é guardado o primeiro argumento de ex2? Isso é feito antes da chamada call.

Exercise

Qual variável é passada como argumento para a função vezes2 ?

Exercise

Escreva abaixo a invocação de vezes2.

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

Após a chamada call, qual o conteúdo de %rax?

Exercise

Juntando suas respostas nas questões de cima, qual é a comparação feita nas linhas ex2+16, ex2+19 ?

Exercise

Com essas informações em mãos, faça uma tradução do código acima para C usando somente if+goto.

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

Quantos argumentos a função acima recebe? De quais tipos? Declare-a abaixo.

Exercise

A função acima faz várias comparações. Liste quais e entre quais argumentos.

Exercise

Onde é armazenado o resultado de cada comparação?

Exercise

Com base em suas respostas acima, faça uma tradução linha a linha da função acima.

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

Quantos argumentos a função acima recebe? De quais tipos? Declare-a abaixo.

Exercise

A função acima faz várias comparações. Liste quais e entre quais argumentos.

Exercise

Onde é armazenado o resultado de cada comparação?

Exercise

Com base em suas respostas acima, faça uma tradução linha a linha da função acima.

Example

Usando as perguntas acima preencha o arquivo de solução no repositório e execute os testes.