Pergunta

Tem sido um montador braço tempo desde que eu última codificado e eu sou um pouco enferrujado sobre os detalhes. Se eu chamar uma função C do braço, eu só precisa se preocupar em salvar r0-R3 e lr, certo?

Se a função C usa quaisquer outros registros, que é responsável por salvar aqueles na pilha e restaurá-los? Em outras palavras, o compilador gerar código para fazer isso para funções C.

Por exemplo, se eu usar r10 em uma função de montador, eu não tenho a empurrar o seu valor na pilha, ou para a memória, e pop / restaurá-lo depois de uma chamada C, não é?

Este é o braço-EABI-gcc 4.3.0.

Foi útil?

Solução

Depende do ABI para a plataforma que você está compilando para. No Linux, há dois ABIs ARM; o velho e o novo. AFAIK, o novo (EABI) está em AAPCS fato da ARM. As definições completas EABI atualmente ao vivo aqui no braço de infocenter .

A partir o AAPCS, §5.1.1 :

  • r0-R3 são os argumentos e scratch registos; r0-R1 são também os registradores de resultado
  • r4-r8 são callee-save registros
  • R9 pode ser um callee-save registo ou não (em algumas variantes de AAPCS é um registo especial)
  • r10-r11 são callee-save registros
  • r12-r15 são registos especiais

A callee-save registo devem ser guardados pelo receptor (em oposição a um chamador-save registo, onde o chamador salva o registo); assim, se esta é a ABI você está usando, você não tem que salvar r10 antes de chamar outra função (a outra função é responsável por salvar-lo).

Editar: Qual compilador você está usando não faz diferença; gcc, em particular, pode ser configurado para vários ABIs diferentes, e pode mesmo ser modificado na linha de comando. Olhando para o código de prólogo / epílogo ele gera não é tão útil, uma vez que é feito sob medida para cada função e o compilador pode usar outras maneiras de salvar um registro (por exemplo, salvando-o no meio de um função).

Outras dicas

Para adicionar-se informações em falta nos registos NEON:

A partir os AAPCS , § 5.1.1 registros do núcleo:

  • r0-R3 são os argumentos e scratch registos; r0-R1 são também os registradores de resultado
  • r4-r8 são callee-save registros
  • R9 pode ser um callee-save registo ou não (em algumas variantes de AAPCS é um registo especial)
  • r10-r11 são callee-save registros
  • r12-r15 são registos especiais

A partir dos AAPCS, §5.1.2.1 VFP registar convenções de uso:

  • s16-s31 (d8-d15, Q4-Q7) deve ser preservado
  • s0-s15 (d0-D7, q0-Q3) e d16-d31 (Q8-Q15) não precisa ser preservada

Original post:
armar-a-c-chamando-convenção neon- registros-to-save

Para 64-bit ARM, A64 (de Procedure Call Standard para o ARM de 64 bits Architecture)

Há trinta e um, 64-bit, general-purpose (inteiro) registra visível para o conjunto A64 instrução; estes são rotulados r0-r30 . Em um contexto de 64 bits destes registros são normalmente referidas usando os nomes x0-x30 ; em um contexto de 32 bits os registros são especificados usando w0-w30 . Além disso, um registo pilha-ponteiro, SP , pode ser utilizado com um número limitado de instruções.

  • SP o ponteiro da pilha
  • r30 LR no link de registro
  • r29 FP O quadro do ponteiro
  • R19 ... R28 registros Callee-salvos
  • r18 A Plataforma Register, se necessário; caso contrário, um registo temporário.
  • r17 IP1 O registo temporário segunda intra-procedimento de chamada (pode ser usado por folheados de chamadas e código PLT); em outras vezes pode ser utilizado como um registo temporário.
  • r16 IP0 A primeira intra-processo-call zero registo (pode ser usado por chamada folheados e código PLT); em outras vezes pode ser utilizado como um registo temporário.
  • R9 ... r15 registros temporários
  • r8 indireta registo de localização de resultado
  • r0 ... r7 Parâmetro / registradores de resultado

As primeiras oito registradores, r0-r7 , são usados ??para passar valores de argumento para uma sub-rotina e retornar valores de resultado de uma função. Eles também podem ser usados ??para armazenar valores intermediários dentro de uma rotina (mas, em geral, apenas entre as chamadas de sub-rotinas).

Registros r16 (IP0) e r17 (IP1) pode ser usado por um elemento de ligação como um registo zero entre uma rotina e qualquer sub-rotina que chama. Eles também podem ser usados ??dentro de uma rotina para manter valores intermediários entre as chamadas de sub-rotinas.

O papel de registo r18 é a plataforma específica. Se uma plataforma ABI tem necessidade de um registo dedicado propósito geral para transportar estado inter-processual (por exemplo, o contexto do thread), então ele deve usar esse registro para esse fim. Se a plataforma ABI não tem esses requisitos, então ele deve usar r18 como um registo temporário adicional. A especificação ABI plataforma deve documentar o uso para este registo.

SIMD

A arquitetura de 64 bits ARM também tem mais um trinta e dois registros, v0-v31 , que pode ser usado por SIMD e operações de ponto flutuante. O nome precisa do registro mudará indicando o tamanho do acesso.

Nota: Ao contrário em AArch32, em AArch64 as vistas de um SIMD e de ponto flutuante de 128 bits e de 64 bits registar não se sobreponham múltiplos registos numa vista mais restrito, então Q1 , d1 e S1 todos se referem à mesma entrada no banco de registradores.

As primeiras oito registradores, v0-v7 , são usados ??para passar valores de argumento para uma sub-rotina e retornar valores de resultado de uma função. Eles também podem ser usados ??para armazenar valores intermediários dentro de uma rotina (mas, em geral, apenas entre as chamadas de sub-rotinas).

Registros v8-v15 deve ser preservado por um receptor através de chamadas de sub-rotinas; os registros restantes ( v0-v7, v16-v31 ) não precisam ser preservadas (ou deveria ser preservado pelo chamador). Além disso, apenas a parte inferior 64-bits de cada valor armazenado em v8-v15 necessidade de ser preservado; é responsabilidade do chamador para preservar os valores maiores.

As respostas de CesarB e Pavel fornecido citações de AAPCS, mas questões em aberto permanecem. Faz o chamado save R9? E sobre r12? E sobre r14? Além disso, as respostas eram muito geral e não específico para o conjunto de ferramentas braço-EABI conforme solicitado. Aqui está uma abordagem prática para descobrir que registram são callee-salvos e quais não são.

O seguinte código C conter um bloco de montagem em linha, que reivindicações para modificar registos r0-r12 e r14. O compilador irá gerar o código para salvar os registros exigidos pela ABI.

void foo() {
  asm volatile ( "nop" : : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14");
}

Use o arm-eabi-gcc-4.7 -O2 -S -o - foo.c linha de comando e adicionar as chaves para a sua plataforma (como -mcpu=arm7tdmi por exemplo). O comando irá imprimir o código assembly gerado em STDOUT. Pode parecer algo como isto:

foo:
    stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    nop
    ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    bx  lr

Note, que o código do compilador gerado salva e restaura r4-r11. O compilador não salva r0-R3, r12. Que restaura r14 (lr alias) é puramente acidental, como eu sei por experiência própria que o código de saída pode também carregar o lr salvos em r0 e depois fazer um "bx r0" em vez de "bx lr". Quer pela inclusão do -mcpu=arm7tdmi -mno-thumb-interwork ou usando -mcpu=cortex-m4 -mthumb obtemos código de montagem um pouco diferente que se parece com isso:

foo:
    stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    nop
    ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc}

Mais uma vez, R4-R11 são salvos e restaurados. Mas r14 (lr alias) não é restaurada.

Para resumir:

  • r0-R3 são não salva-callee
  • R4-r11 são salvos pelo callee
  • r12 (ip alias) é não salva-callee
  • r13 (aliás sp) é salvo-callee
  • r14 (lr alias) é não salva-callee
  • r15 (pc alias) é o contador de programa e está definido para o valor de lr antes da chamada de função

Isto é, pelo menos para o padrão do braço-EABI-gcc. Há opções de linha de comando (em particular o interruptor -mabi) que podem influenciar os resultados.

Há também diferença, pelo menos na arquitetura Cortex M3 para chamada de função e de interrupção.

Se ocorrer um Interrupção ele vai fazer impulso automático R0-R3, R12, LR, PC na pilha e quando formulário de devolução IRQ POP automático. Se você usar outros registros na rotina IRQ você tem que empurrar / pop-los na pilha manualmente.

Eu não acho que isso IMPULSO automática e POP é feita para uma chamada de função (instrução de salto). Se convenção diz R0-R3 pode ser usado apenas como um argumento, resultado ou registradores de rascunho, por isso não há necessidade de armazená-los antes chamada de função, porque não deve haver qualquer valor usado mais tarde, após retorno de função. Mas mesmo que em uma interromper você tem que armazenar todos os outros registros de CPU, se você usá-los em sua função.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top