문제

팔 어셈블러를 마지막으로 코딩한 지 꽤 시간이 지났고 세부 사항에 대해 약간 녹슬었습니다.arm에서 C 함수를 호출하면 r0-r3과 lr만 저장하면 되겠죠?

C 함수가 다른 레지스터를 사용하는 경우 해당 레지스터를 스택에 저장하고 복원해야 합니까?즉, 컴파일러는 C 함수에 대해 이 작업을 수행하는 코드를 생성합니다.

예를 들어 어셈블러 함수에서 r10을 사용하는 경우 해당 값을 스택이나 메모리에 푸시하고 C 호출 후에 팝/복원할 필요가 없습니다. 그렇죠?

arm-eabi-gcc 4.3.0용입니다.

도움이 되었습니까?

해결책

그것은에 달려 있습니다 아비 컴파일하는 플랫폼의 경우. Linux에는 두 개의 팔 아비스가 있습니다. 오래된 것과 새로운 것. Afaik, 새로운 것 (Eabi)은 실제로 ARM의 AAPC입니다. 완전한 EABI 정의는 현재 살고 있습니다 여기 ARM의 Infocenter에 있습니다.

에서 AAPCS, §5.1.1:

  • R0-R3 인수와 스크래치 레지스터입니다. R0-R1 또한 결과 레지스터입니다
  • R4-R8 Callee-save 레지스터입니다
  • R9 Callee-save 레지스터 일 수 있습니다.
  • R10-R11 Callee-save 레지스터입니다
  • R12-R15 특별 레지스터입니다

Callee-save 레지스터는 Callee에 의해 저장되어야합니다 (발신자가 레지스터를 저장하는 발신자 사무소 등록부에 반대). 그래서, 만약에 이것은 당신이 사용하는 ABI입니다. 다른 함수를 호출하기 전에 R10을 저장할 필요가 없습니다 (다른 기능은 저장을 담당합니다).

편집하다: 사용중인 컴파일러는 차이가 없습니다. 특히 GCC는 특히 여러 다른 ABI에 대해 구성 할 수 있으며 명령 줄에서도 변경할 수도 있습니다. Prologue/epilogue 코드를 살펴보면 각 함수에 맞게 조정되므로 유용하지 않습니다. 그리고 컴파일러는 레지스터를 저장하는 다른 방법 (예 : 함수 중간에 저장)을 사용할 수 있습니다.

다른 팁

네온 레지스터에 누락 된 정보를 추가하려면 :

에서 AAPC, §5.1.1 핵심 레지스터 :

  • R0-R3 인수와 스크래치 레지스터입니다. R0-R1 또한 결과 레지스터입니다
  • R4-R8 Callee-save 레지스터입니다
  • R9 Callee-save 레지스터 일 수 있습니다.
  • R10-R11 Callee-save 레지스터입니다
  • R12-R15 특별 레지스터입니다

AAPCS에서 §5.1.2.1 VFP 레지스터 사용 규칙 :

  • S16 – S31 (D8 – D15, Q4 – Q7) 보존해야합니다
  • S0 – S15 (D0 – D7, Q0 – Q3) 그리고 D16 – D31 (Q8 – Q15) 보존 할 필요가 없습니다

원본 게시물 :
무기-콜링-전환-노동-등록

64 비트 암의 경우 A64 (절차에서 ARM 64 비트 아키텍처에 대한 표준 전화)

A64 명령 세트에 볼 수있는 31 개의 64 비트, 일반 목적 (정수) 레지스터가 있습니다. 이것들은 레이블이 붙습니다 R0-R30. 64 비트 컨텍스트 에서이 레지스터는 일반적으로 이름을 사용하도록 언급됩니다. x0-x30; 32 비트 컨텍스트에서 레지스터는 사용하여 지정됩니다. W0-W30. 또한 스택 포인터 레지스터, sp, 제한된 수의 지침과 함께 사용할 수 있습니다.

  • sp 스택 포인터
  • R30 LR 링크 레지스터
  • R29 FP 프레임 포인터
  • R19… R28 Callee-Saved Registers
  • R18 필요한 경우 플랫폼 레지스터; 그렇지 않으면 임시 등록.
  • R17 IP1 두 번째 프로세서 내 임시 레지스터 (통화 베니어 및 PLT 코드에서 사용할 수 있음); 다른 시간에는 임시 레지스터로 사용될 수 있습니다.
  • R16 IP0 첫 번째 프로세서 내 스크래치 레지스터 (통화 베니어 및 PLT 코드에서 사용할 수 있음); 다른 시간에는 임시 레지스터로 사용될 수 있습니다.
  • R9… R15 임시 등록
  • R8 간접 결과 위치 레지스터
  • R0… R7 매개 변수/결과 레지스터

처음 8 개의 레지스터, R0-R7, 인수 값을 서브 루틴으로 전달하고 함수에서 결과 값을 반환하는 데 사용됩니다. 또한 일상 내에서 중간 값을 유지하는 데 사용될 수 있습니다 (그러나 일반적으로 서브 루틴 호출 사이에만).

등록 R16 (IP0) 그리고 R17 (IP1) 링커에 의해 루틴과 호출하는 서브 루틴 사이의 스크래치 레지스터로 사용할 수 있습니다. 또한 서브 루틴 호출 사이에 중간 값을 유지하기 위해 루틴 내에서 사용될 수 있습니다.

레지스터의 역할 R18 플랫폼 별입니다. 플랫폼 ABI에 전용 범용 레지스터가 필요한 경우 (예 : 스레드 컨텍스트)이 목적 으로이 레지스터를 사용해야합니다. 플랫폼 ABI에 그러한 요구 사항이없는 경우 R18을 추가 임시 레지스터로 사용해야합니다. 플랫폼 ABI 사양은이 레지스터의 사용법을 문서화해야합니다.

ARM 64 비트 아키텍처에는 32 개의 레지스터가 더 있습니다. V0-V31, SIMD 및 부동 소수점 작업에서 사용할 수 있습니다. 레지스터의 정확한 이름은 액세스의 크기를 나타내는 변경됩니다.

메모: Aarch32와 달리 Aarch64의 128 비트 및 64 비트 전망은 SIMD 및 Float-Point 레지스터의 뷰가 좁은보기에서 여러 레지스터와 겹치지 않습니다. 따라서 Q1, D1 및 S1은 모두 레지스터 은행에서 동일한 항목을 나타냅니다.

처음 8 개의 레지스터, V0-V7, 인수 값을 서브 루틴으로 전달하고 함수에서 결과 값을 반환하는 데 사용됩니다. 또한 일상 내에서 중간 값을 유지하는 데 사용될 수 있습니다 (그러나 일반적으로 서브 루틴 호출 사이에만).

등록 V8-V15 서브 루틴 통화를 통해 칼리에 의해 보존되어야합니다. 나머지 레지스터 (V0-V7, V16-V31) 보존 할 필요가 없습니다 (또는 발신자가 보존해야 함). 또한, 각 값의 하단 64 비트 만 V8-V15 보존해야합니다. 더 큰 값을 보존하는 것은 발신자의 책임입니다.

CesarB와 Pavel의 답변은 AAPCS의 인용문을 제공했지만 아직 해결되지 않은 문제가 남아 있습니다.수신자가 r9를 저장합니까?r12는 어떻습니까?r14는 어떻습니까?게다가 답변은 매우 일반적이었고 요청한 대로 arm-eabi 툴체인에만 국한되지 않았습니다.다음은 호출 수신자가 저장한 레지스터와 그렇지 않은 레지스터를 알아내는 실용적인 접근 방식입니다.

다음 C 코드에는 레지스터 r0-r12 및 r14를 수정한다고 주장하는 인라인 어셈블리 블록이 포함되어 있습니다.컴파일러는 ABI에 필요한 레지스터를 저장하는 코드를 생성합니다.

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

명령줄 사용 arm-eabi-gcc-4.7 -O2 -S -o - foo.c플랫폼에 대한 스위치를 추가합니다(예: -mcpu=arm7tdmi 예를 들어).이 명령은 생성된 어셈블리 코드를 STDOUT에 인쇄합니다.다음과 같이 보일 수 있습니다.

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

컴파일러 생성 코드는 r4-r11을 저장하고 복원합니다.컴파일러는 r0-r3, r12를 저장하지 않습니다.r14(별칭 lr)를 복원하는 것은 종료 코드가 저장된 lr을 r0에 로드한 다음 "bx lr" 대신 "bx r0"을 수행할 수도 있다는 것을 경험을 통해 알고 있으므로 순전히 우연입니다.다음 중 하나를 추가하여 -mcpu=arm7tdmi -mno-thumb-interwork 또는 사용하여 -mcpu=cortex-m4 -mthumb 다음과 같이 약간 다른 어셈블리 코드를 얻습니다.

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

다시 r4-r11이 저장되고 복원됩니다.그러나 r14(별칭 lr)는 복원되지 않습니다.

요약:

  • r0-r3은 ~ 아니다 수신자가 저장한
  • r4-r11은 수신자에 의해 저장됩니다.
  • r12(별칭 IP)는 ~ 아니다 수신자가 저장한
  • r13(별칭 sp)은 호출 수신자가 저장됩니다.
  • r14(별칭 lr)는 ~ 아니다 수신자가 저장한
  • r15(별칭 pc)는 프로그램 카운터이며 함수 호출 이전에 lr 값으로 설정됩니다.

최소한 arm-eabi-gcc의 기본값은 유지됩니다.결과에 영향을 미칠 수 있는 명령줄 스위치(특히 -mabi 스위치)가 있습니다.

기능 호출 및 인터럽트를위한 피질 M3 아키텍처에는 적어도 차이가 있습니다.

인터럽트가 발생하면 자동 푸시 R0-R3, R12, LR, PC가 스택에 있고 리턴이 IRQ 자동 팝을 형성 할 때가됩니다. IRQ 루틴에서 다른 레지스터를 사용하는 경우 수동으로 스택에 푸시/팝해야합니다.

이 자동 푸시와 팝이 함수 호출 (Jump Instruction)을 위해 만들어 졌다고 생각하지 않습니다. 컨벤션에서 R0-R3이 인수, 결과 또는 스크래치 레지스터로만 사용할 수 있다고 말하면 기능 통화 후에 사용 된 값이 없기 때문에 기능 호출 전에 저장할 필요가 없습니다. 그러나 인터럽트에서 동일하게 기능에 사용하는 경우 다른 모든 CPU 레지스터를 저장해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top