Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

8179
1390
307630


[Arm프로세서] AAPCS: Armv7: 함수 인자의 갯수는 4개 이하로 제한 Armv7: 함수 호출 규약

함수에 전달되는 인자는 4개 이하로 제한하는 것이 좋습니다. 함수의 인자의 갯수가 5개를 넘어가면, 프로세스의 스택 공간에 인자를 저장해 전달하기 때문입니다.

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

01 int add_func(int a, int b, int c, int d, int e)
02 {
03 int result = a + b + c + d + e;
04 printf("a:%d, b:%d, c:%d, d:%d, e:%d \n", 
05 a, b, c, d, e);
06
07 return result;
08 }
09
10 int main(void) 
11 {
12 int a = 1, b = 2, c = 3, d = 4, e = 5; 
13
14 int res = add_func(a, b, c, d, e);
15 printf("add result = %d \n", res);
16 
17 return 0;
18}

14번째 줄을 보면 add_func() 함수에 전달되는 인자의 갯수가 5개입니다. 이 경우 함수에 전달되는 인자는 어느 레지스터에 저장될까요? 위 코드를 컴파일하면 생성되는 어셈블리 코드에서 그 답을 찾을 수 있습니다. 다음 어셈블리 명령어를 보면서 이 내용을 더 자세히 알아봅시다.

01 000104b0 <main>:
02 
03 int main(void) 
04 {
05   104b0: e92d4800  push {fp, lr}
06   104b4: e28db004  add fp, sp, #4
07   104b8: e24dd020  sub sp, sp, #32
08 int a = 1, b = 2, c = 3, d = 4, e = 5; 
...
09 int res = add_func(a, b, c, d, e);
10   104e4: e51b3018  ldr r3, [fp, #-24] ; 0xffffffe8
11   104e8: e58d3000  str r3, [sp]
12   104ec: e51b3014  ldr r3, [fp, #-20] ; 0xffffffec
13   104f0: e51b2010  ldr r2, [fp, #-16]
14   104f4: e51b100c  ldr r1, [fp, #-12]
15   104f8: e51b0008  ldr r0, [fp, #-8]
16   104fc: ebffffcc  bl 10434 <add_func>

위 어셈블리 명령어에서 눈여겨 볼 부분은 다음과 같이 11~15번째 줄인데, add_func() 함수의 주소로 분기하기 전에 인자를 저장하는 루틴입니다.

11   104e8: e58d3000  str r3, [sp]
12   104ec: e51b3014  ldr r3, [fp, #-20] ; 0xffffffec
13   104f0: e51b2010  ldr r2, [fp, #-16]
14   104f4: e51b100c  ldr r1, [fp, #-12]
15   104f8: e51b0008  ldr r0, [fp, #-8]

12~15번째 줄을 쉽게 설명하면, R0, R1, R2, R3 레지스터에 함수에 전달되는 인자를 저장하는 동작입니다. 12~15번째 줄은 비슷한 패턴의 명령어인데, 이 중 한 가지 명령어만 알아봅시다. 15번째 줄에 있는 명령어는 "fp 레지스터의 값을 기준으로 -8바이트에 위치한 데이터를 r0 레지스터에 로딩하는 동작입니다.

이어서 11번째 줄을 보겠습니다.

11   104e8: e58d3000  str r3, [sp]
 
r3 레지스터의 값을 현재 스택 공간에 저장하는 동작입니다. str는 store 명령어인데, sp 레지스터가 가리키는 주소에 r3 레지스터의 값을 저장하게 됩니다. 

이 동작으로 함수에 전달되는 인자의 갯수가 5개이면, 4개의 인자까지는 R0, R1, R2, R3 레지스터까지 인자를 저장하고, 5번째 인자는 스택 공간에 저장한다라는 사실을 알 수 있습니다.

이를 일반화해서 "함수에 전달되는 인자의 갯수가 4개를 넘어서면, 4개까지는 R0~R3 레지스터에 저장하고, 5개 이후는   프로세스의 스택 공간에 인자를 저장한다"고 할 수 있습니다.
구조 설계 관점으로 함수는 한 가지 기능을 수행하도록 작성하는 것도 중요하지만, 함수에 전달되는 인자의 갯수가 5개 이상인지 확인할 필요가 있습니다. C 코드로 함수의 인자의 갯수가 늘어나는게 별 게 아닌 것 같지만, Armv7 아키텍처 관점으로 보면 어셈블리 명령어의 양이 늘어나 복잡도가 커집니다.

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




덧글

댓글 입력 영역