[왕초보 임베디드-C 공부 일기] 3. 함수(2) - 임베디드 시스템 내 동작

   위성이나 로버 같은 제한된 임베디드 시스템에서 함수의 동작 원리를 이해하려면 메모리와 레지스터의 관점에서 이해하는 것이 필요하다. 컴퓨터에서는 메모리가 넉넉해서 함수를 자유롭게 사용해도 성능에 큰 영향이 없지만, 임베디드에서는 함수 하나를 호출할 때마다 상당한 비용이 든다.

1. 저장 위치 : 플래시 메모리(ROM)


   -함수는 변수처럼 값이 변하는 게 아니라, '고정된 명령어들의 집합'이므로 전원이 꺼져도 지워지지 않는 플래시 메모리(ROM)에 저장된다. 
   -플래시 메모리 내부의 Code Segment(.text) 부분에 함수를 이루는 기계어 코드들이 저장된다. 
   +함수 안에서 const(.rodata)로 선언된 읽기 전용 데이터도 함수와 동일한 영역에 저장된다. 

2. 메모리의 관점 : 스택(Stack)의 역할

   함수가 호출되어 실제로 일을 시작하면, RAM 내에서 지역변수와 함수를 담당하는 스택(Stack)이라는 공간을 사용한다. 
   (RAM내에서 전역 변수를 담당하는 공간은 .data 와 .bss영역이다.)

   -스택 프레임(Stack Frame)의 생성
      함수가 호출될 때마다 RAM의 스택 영역에는 '스택 프레임'이라는 호출된 함수를 위한 임시 공간이 생긴다. 여기에는 다음 내용들이 임시 저장된다. 
   1) 지역 변수 : 함수 안에서만 쓰는 변수들
   2) 백업된 레지스터 : 다른 함수가 쓰던 레지스터 값들을 잠시 옮겨 둔 값
   3) 생명 주기 : 함수가 return을 만나 종료되면, 이 스택 프레임은 즉시 소멸한다.

   +재귀 호출 금지(No Recursion, MISRA-C Rule 17.2)
   -함수가 자기 자신을 계속 호출(재귀)하면, RAM의 스택 영역에 스택 프레임이 계속 쌓임.
   -PC나 서버와 달리, 임베디드 시스템의 RAM은 아주 작기 때문에, 재귀로 인해 스택이 꽉 차서 넘치는 스택 오버플로우(Stack overflow)가 발생하면,
    시스템은 멈추거나 예측 불가능한 동작(Crash)을 일으킴.
   -모든 재귀 알고리즘은 필요한 경우 반복문(for, while)로 바꿔서 스택 사용량을 예측 가능하게 해야 함. 

3. 레지스터의 관점 : 성능 최적화

   기존에는 "호출된 함수는 스택에 쌓인다."고 설명하였지만, AAPCS 호출 규약에 의거한 최신 임베디드(ARM Cortex-M)에서는 RAM내의 스택을 사용하기 전에 CPU내의 범용 레지스터를 먼저 사용한다. 

   1)레지스터 전달
      -신속한 처리를 위해 함수 내 매개변수 1번~4번까지는 RAM을 거치지 않고, CPU내부의 범용 레지스터(R0, R1, R2, R3)에 직접 실려서 전달된다.
      -결과값(Return Value)도 계산이 끝나면 R0 레지스터에 담겨서 반환된다.
      -그래서 임베디드 함수를 설계할 때에는 매개변수를 4개 이하로 줄이는 것이 성능 최적화하는 좋은 방법 중 하나이다.

   2)스택 전달
      -매개변수가 5개가 넘어가거나, 규모가 큰 구조체를 값으로 전달하려 하면, 이때부터는 스택(RAM)에 전달된다. 이는 시스템 성능을 떨어뜨리는
       오버헤드(Overhead)가 된다.

   3)CPU 내 레지스터들의 역할
      CPU가 함수를 실행한다는 건, '주소를 옮기는 행위'와 같다. 이때 CPU 내부의 레지스터들이 각자의 역할에 따라 바쁘게 움직인다.
      -PC(Program Counter) : 현재 읽고 있는 줄 확인
       평소에는 다음에 실행할 명령어의 주소를 가리키다가, 함수가 호출되면 함수의 시작 주소(플래시 메모리)로 옮긴다.
      -LR(Link Register) : 돌아가야 할 위치 기억
       PC가 함수의 시작 주소로 옮기기 전에, 원래 위치 주소를 LR에 적어둔다. 함수가 끝나면(Return), CPU는 LR을 보고 원래 위치로 이동한다. 
      -SP(Stack Pointer) : 지역 변수 위치 기억
       RAM에 있는 스택 프레임의 꼭대기 위치 주소를 기억한다.