1.3 Chamadas de Procedimentos

Linguagem Assembly

O Procedure Call Standard for the Arm Architecture - AAPCS define como rotinas podem ser escritas separadamente, compiladas separadamente e montadas separadamente para trabalharem juntas. Descreve um contrado entre a rotina que chama e a rotina que é chamada que define:

  • Obrigações na rotina chamadora para criar um estado de programa no qual a rotina chamada possa começar a executar;
  • Obrigações na rotina chamada para preservar o estado do programa do chamador através da chamada;
  • Os direitos da rotina chamada para alterar o estado do programa que fez a chamada.

Registradores de máquina

A arquitetura ARM define um conjunto de instruções básicas, além de várias instruções adicionais implementadas pelos coprocessadores. O conjunto principal de instruções pode acessar os registradores principais e os coprocessadores podem fornecer registradores adicionais que estão disponíveis para operações específicas.

Registradores do núcleo

  • Os nomes dos registradores podem aparecer no assembly em maiúsculas ou minúsculas;
  • Existem 16 registradores principais (inteiros) de 32 bits visíveis aos conjuntos de instruções ARM e Thumb. Estes são rotulados r0-r15 ou R0-R15;
  • Os primeiros quatro registradores r0-r3 (a1-a4) são usados para passar valores de argumentos para uma sub-rotina e para retornar o valor do resultado de uma função. Eles também podem ser usados para guardar valores intermediários dentro de uma rotina (mas, em geral, somente entre chamadas de sub-rotina);
  • Normalmente, os registradores r4-r8, r10 e r11 (v1-v5, v7 e v8) são usados para armazenar os valores das variáveis locais de uma rotina;
  • Uma sub-rotina deve preservar o conteúdo dos registradores r4-r8, r10, r11 e SP (e r9 nas variantes PCS que designam r9 como v6).

Por exemplo, para tipos inteiros ou de ponteiro, especifica que: (Calling assembly functions from C and C++)

  • Os registradores R0-R3 passam os valores dos argumentos para a função chamada, com argumentos subsequentes passados na pilha.
  • O registrador R0 retorna o valor do resultado para a função chamadora.
  • As funções chamadoras devem preservar os registradores R0-R3 e R12, porque esses registradores podem ser modificados pela função chamada.
  • As funções chamadas devem preservar os registradores R4-R11 e LR, porque esses registradores não podem ser modificados pela função chamada.

Registradores da unidade de ponto flutuante

  • A tecnologia VFP (Vector Floating Point) é uma extensão do coprocessador FPU (unidade de ponto flutuante) para a arquitetura ARM;
  • O co-processador VFP-v2 possui 32 registradores de precisão simples, s0-s31, que também podem ser acessados como 16 registradores de precisão dupla, d0-d15 (com d0 se sobrepondo a s0, s1; d1 se sobrepondo a s2, s3; etc);
  • Além disso, existem 3 ou mais registradores do sistema, dependendo da implementação;
  • O VFP-v3 adiciona mais 16 registradores de precisão dupla d16-d31, mas não há contrapartidas adicionais de precisão simples;
  • O Advanced SIMD Extension usa o conjunto de registradores VFP, usando os registradores de precisão dupla para vetores de 64 bits e, além disso, definindo registradores de quatro palavras (com q0 se sobrepondo a d0, d1; e q1 se sobrepondo d2, d3; etc) para vetores de 128 bits;
  • Os registradores s16-s31 (d8-d15, q4-q7) devem ser preservados entre todas as chamadas de sub-rotina; os registradores s0-s15 (d0-d7, q0-q3) não precisam ser preservados (e podem ser usados para transmitir argumentos ou retornar resultados em variantes de chamada de procedimento padrão).
  • Os registradores d16-d31 (q8-q15), se presentes, não precisam ser preservados.

Arquitetura de 64 bits: (Procedure Call Standard for the Arm 64-bit Architecture)

SIMD e Registradores de Ponto Flutuante:

  • A arquitetura Arm 64-bit também possui trinta e dois registradores adicionais, v0-v31, que podem ser usados pelas operações SIMD e de ponto flutuante. O nome preciso do registrador muda, indicando o tamanho do acesso;
  • Ao contrário de AArch32, no AArch64 as visões de 128 bits e 64 bits de um registrador SIMD e de ponto flutuante não sobrepõem múltiplos registradores de uma visão menor, então q1, d1 e s1 se referem à mesma entrada no banco de registradores;
  • Os primeiros oito registradores, v0-v7, são usados para passar valores de argumentos para uma sub-rotina e para retornar valores de resultados de uma função. Também podem ser usados para guardar valores intermediários dentro de uma rotina (mas, em geral, somente entre chamadas de sub-rotina);
  • Os registradores v8-v15 devem ser preservados pela rotina que faz a chamada nas chamadas de sub-rotina; os registradores restantes (v0-v7, v16-v31) não precisam ser preservados (ou devem ser preservados pela chamadora). Além disso, apenas os 64 bits inferiores de cada valor armazenado em v8-v15 precisam ser preservados; é responsabilidade da chamadora preservar valores superiores;
  • O FPSR é um registrador de status que contém os bits de exceção cumulativa da unidade de ponto flutuante. Contém os campos IDC, IXC, UFC, OFC, DZC, IOC e QC. Esses campos não são preservados em uma interface pública e podem ter qualquer valor na entrada de uma sub-rotina.