본문 바로가기

시스템 소프트웨어 개발을 위한 Arm 아키텍처의 구조와 원리/11장: AAPCS(함수 호출 규약)

[Arm][AAPCS] 스택 오염이나 스택 오버플로우 현상을 만나면 개발자들은 왜 당황해할까?

실전 프로젝트에서 어떤 기능을 구현하는데 50%정도의 노력과 리소스가 들면, 대부분 최소 50% 이상은 버그를 수정하는데 시간을 할애합니다. 이 과정에서 수 많은 버그를 만나는데 잡기 쉬운 버그가 있고 분석을 시작하기 조차 어려운 버그도 있습니다. 처음 겪었을 때 가장 당황하는 버그가 스택 이슈(스택 오버플로우/스택 오염)로 인한 크래시입니다. 주요 증상은 아래와 같습니다.

 

  • 갑자기 이상한 주소로 프로그램 카운터가 점프를 한다.
  • 지역 변수의 값이 이상한 쓰레기 값으로 바뀐다.
  • 갑자기 크래시나 폴트가 발생해 실행하던 프로그램이 멈춘다.

이런 증상은 대부분 스택이 오염됐을 때 생기는 증상인데 AAPCS의 동작 원리를 모른채, 이런 현상을 겪으면 어디부터 분석을 시작해야 할 지 모릅니다. 그 이유는 무엇일까요?

“바로 디버깅용 프로그램이나 로그에서 문제가 발생할 시점의 콜 스택을 제대로 
출력하지 않기 때문입니다.” 

 

디버깅용 프로그램이나 로그에서 “스택 오염이 발생했다”라고 친절하게 알려주면 얼마나 좋을까요? 하지만 디버깅 프로그램이나 로그가 콜 스택을 뿌려 줄 때는 프로세스의 스택 공간에 저장된 데이터(레지스터 값)를 참고하는데, 스택이 오염돼 스택에 저장된 데이터가 깨져 있으면 콜 스택을 출력조차 못합니다. 

아래는 스택이 오염돼 GDB 프로그램이 제대로 콜 스택을 출력하지 못하는 예시입니다.

 

(출처: 
https://stackoverflow.com/questions/9809810/gdb-corrupted-stack-frame-how-to-debug)

Program received signal SIGSEGV, Segmentation fault.
0x00000002 in ?? ()
(gdb) bt
#0  0x00000002 in ?? ()
#1  0x00000001 in ?? ()
#2  0xbffff284 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb)

 


디버깅 프로그램도 문제가 생겼을 때 제대로 콜 스택을 출력 못하는 상황에서 이런 증상을 만나면 SW 개발자는 어떻게 디버깅을 해야 할까요?

그런데 차근 차근 각각의 함수들이 어떤 원리로 호출됐는지 AAPCS 관점으로 세세하게 분석하면 자연히 문제 해결로 이어지는 경우가 많습니다. 


[정보]
실전 프로젝트에서 이런 버그를 만나면 대부분 야근을 하면서 고생을 합니다. 일정 내에 버그를 수정해야 하기 때문이죠. 이런 문제를 해결하는 과정에서 AAPCS의 상세 내용을 세세히 파악하게 됩니다. 문제를 해결하고 나면 'AAPCS와 관련된 내용을 미리 알았으면 좋았을 텐데'라며 아쉬워합니다.



#Armv8-A,  
#AAPCS,  
#스택오버플로,