반응형
AAPCS(Calling Convention) 을 알아야 하는 이유
프로그래밍의 근본 동작 원리 파악이 가능
- 실제 Arm 코어는 c 코드가 아니라 어셈블리 명령어를 실행함
- 대부분 c 코드는 함수로 구성 됨
안정적이고 최적화된 이쁜 코드 작성 할 수 있는 기반 지식
- 함수에 전달되는 인자의 갯수
- 프로세스의 스택을 최대한 사용하지 않는 코드 설계를 해야 함
디버깅 실력을 키우고 이는 문제 해결 능력으로 이어짐
- 스택 오버플로우, 스택 Corruption
- 콜 스택 복원
objdump 나 trace32 를 통해 어셈블리 영역을 볼 수 있다.
또한, 함수 호출 시 인자의 갯수를 전달 할 수 있는 레지스터는 8개로 한정되어있다.
8개 초과 시 해당 프로세스의 스택영역에 할당하여 컨텍스트 스위칭을 진행하게 된다.
물론 프로세스의 리소스가 여유로운 경우가 많아 큰 문제는 없을 수 있지만,
개발자가 이를 모르고 과도하게 사용할 경우 결국 문제를 일으킬 수 있다.
이러한 경우 struct 를 이용하여 함수 호출을 하는 방법이 있다.
아래는 실제 커널 소스로 확인이 가능하다.
#ifdef __ARCH_WANT_SYS_CLONE
#ifdef CONFIG_CLONE_BACKWARDS
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
int __user *, parent_tidptr,
unsigned long, tls,
int __user *, child_tidptr)
#elif defined(CONFIG_CLONE_BACKWARDS2)
SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags,
int __user *, parent_tidptr,
int __user *, child_tidptr,
unsigned long, tls)
#elif defined(CONFIG_CLONE_BACKWARDS3)
SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,
int, stack_size,
int __user *, parent_tidptr,
int __user *, child_tidptr,
unsigned long, tls)
#else
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
int __user *, parent_tidptr,
int __user *, child_tidptr,
unsigned long, tls)
#endif
{
struct kernel_clone_args args = {
.flags = (lower_32_bits(clone_flags) & ~CSIGNAL),
.pidfd = parent_tidptr,
.child_tid = child_tidptr,
.parent_tid = parent_tidptr,
.exit_signal = (lower_32_bits(clone_flags) & CSIGNAL),
.stack = newsp,
.tls = tls,
};
return kernel_clone(&args);
}
#endif
ftrace 나 trace32 등을 통해 콜스텍 확인이 가능하며 trace32 의 경우 여러 명령어를 통해
어셈블리와 덤프로 해당 주소 영역을 따라 갈 수 있다.
해당 내용 관련해서는 구글링을 통해 자세히 기술 하신분들이나 문서로 확인이 가능하다.
위 내용은 고급 프로그래머가 되기 위한 가장 기본적인 내용이라고 생각한다.
이러한 내용을 잘 모르는 경우가 많기는 하지만 이 글을 통해 더 알아 갈 수 있는 기회가 되었길 바란다.
반응형
'Embedded > Arm 아키텍처' 카테고리의 다른 글
[Arm 아키텍처] ARM 레지스터 : 스페셜 레지스터 (0) | 2022.02.19 |
---|