Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

9365
557
421924


[Arm프로세서] AAPCS: Armv8: C 코드 최적화 - 함수 인자의 갯수는 9개 이하로 제한 Armv8: 함수 호출 규약

6.4 절에서 Armv7 아키텍처에서 다룬 AAPCS는 실무에 적용할 만한 실용적인 내용이 많다고 설명했습니다. Armv8 아키텍처의 AAPCS도 마찬가지입니다.

이번 절에서는 Armv8 아키텍처의 AAPCS에서 성능 개선을 위해 고려해야 할 2가지 내용을 소개합니다.

Armv8 아키텍처의 AAPCS로 관점으로 보면 함수 인자의 갯수는 9개 이하로 제한하는게 좋습니다. 함수의 인자의 갯수가 9개를 넘어가면, 프로세스의 스택 공간에 인자를 저장해 전달하기 때문입니다.

하지만 함수의 인자의 갯수가 4개를 넘어서면 코드의 가독성이 떨어지고, 인자를 연산한 결과를 저장하기 위해 프로세스의 스택 공간에 엑세스하는 명령어가 늘어납니다. 되도록이면 함수에 전달되는 인자는 4개까지 지정하는 것이 좋습니다.

이번에는 함수에 10개의 인자를 전달하는 예제 코드를 분석하면서, 이 내용에 대해 조금 더 짚어봅시다. 

void test_aapcs(void)
{
    int res = 0;
    int a, b, c, d, e, f, g, h, i, j;

    a = 1, b = 2, c = 3, d = 4, e = 5, f = 6, g = 7, h = 8, i = 9, j = 10;

    res = add_func(a, b, c, d, e, f, g, h, i, j);
    printf("res = %d \n", res);
}

위 코드에서 add_func() 함수에 전달되는 인자의 갯수는 10개입니다.

이번 장에서 배운 내용을 종합하면 1~8번째 인자까지는 X0-X7 레지스터에 저장되고,
9~10번째 인자는 프로세스의 스택 공간에 저장될 것이라 예상할 수 있습니다.

이번에는 test_aapcs() 함수를 어셈블리 명령어 포멧으로 확인해보겠습니다.

01 <test_aapcs>:
02   d10143ff    sub sp, sp, #0x50
03   f9000bfe    str x30, [sp, #16]
04   b9004fff    str wzr, [sp, #76]
05   52800020    mov w0, #0x1                    // #1
06   b9004be0    str w0, [sp, #72]
07   52800040    mov w0, #0x2                    // #2
08   b90047e0    str w0, [sp, #68]
09   52800060    mov w0, #0x3                    // #3
10   b90043e0    str w0, [sp, #64]
11   52800080    mov w0, #0x4                    // #4
12   b9003fe0    str w0, [sp, #60]
13   528000a0    mov w0, #0x5                    // #5
14   b9003be0    str w0, [sp, #56]
15   528000c0    mov w0, #0x6                    // #6
16   b90037e0    str w0, [sp, #52]
17   528000e0    mov w0, #0x7                    // #7
18   b90033e0    str w0, [sp, #48]
19   52800100    mov w0, #0x8                    // #8
20   b9002fe0    str w0, [sp, #44]
21   52800120    mov w0, #0x9                    // #9
22   b9002be0    str w0, [sp, #40]
23   52800140    mov w0, #0xa                    // #10
24   b90027e0    str w0, [sp, #36]
25   b94027e0    ldr w0, [sp, #36]
26   b9000be0    str w0, [sp, #8]
27   b9402be0    ldr w0, [sp, #40]
28   b90003e0    str w0, [sp]
29   b9402fe7    ldr w7, [sp, #44]
30   b94033e6    ldr w6, [sp, #48]
31   b94037e5    ldr w5, [sp, #52]
32   b9403be4    ldr w4, [sp, #56]
33   b9403fe3    ldr w3, [sp, #60]
34   b94043e2    ldr w2, [sp, #64]
35   b94047e1    ldr w1, [sp, #68]
36   b9404be0    ldr w0, [sp, #72]
37   97ffffb9    bl  ffffff80085b24d4 <add_func>

05~24번째 줄은 스택의 가장 아래 주소부터 설정된 지역 변수의 값을 저장하는 동작입니다.

29~36번째 줄을 보면 8번째 인자까지 X0-X7 레지스터에 add_func() 함수에 전달되는 인자를 저장합니다. 그렇다면 add_func() 함수에 전달되는 9~10번째 인자는 어디에 저장될까요?

아래 20~23번째 줄과 같이 프로세스의 스택 주소(sp+44, sp+40)에 저장됩니다.

20   b9002fe0    str w0, [sp, #44]
21   52800120    mov w0, #0x9                    // #9
22   b9002be0    str w0, [sp, #40]
23   52800140    mov w0, #0xa                    // #10

이처럼 함수에 전달되는 인자의 갯수가 9개 이상이면 프로세스의 스택 공간에 인자를 저장하므로, 어셈블리 명령어가 늘어납니다. 이에 비례해서 명령어가 실행되므로 Armv8 아키텍처의 성능 관점으로 보면 인자의 개수는 되도록 8개 이하로 적용하는게 바람직합니다.

Armv8 아키텍처: AAPCS(함수호출 규약)

   ❑ 스택과 관련된 명령어 
      * stp 명령어  
      * sub 명령어  
      * ldp 명령어  
   ❑ 브랜치와 복귀 명령어
      * bl 명령어  
      * RET 명령어
AAPCS와 C 코드 최적화


Written by <디버깅을 통해 배우는 리눅스 커널의 구조와 원리> 저자




핑백

덧글

댓글 입력 영역