4학년 1학기 전공/컴파일러
[컴파일러] Chapter 6. Activation Records
시데브
2025. 4. 23. 21:24
경희대학교 허선영 교수님의 컴파일러 수업을 기반으로 정리한 글입니다.
0. Backgrounds
Process in Memory
- Memory Layout
- Text section: 프로그램 코드
- Data section: (uninitialized and initialized) 전역 변수
- Stack section: 일시적 데이터
- 함수 파라미터, 리턴 어드레스, 지역 변수
- Heap section: 런타임에 동적으로 할당되는 메모리
ELF File Format
- Excecutable and Linkable Format
- source program -> compiler -> target binary
- target binary의 포맷 중 하나가 ELF
- 컴파일 결과를 sections 나누어서 저장
- 단순히 machine codes만 저장하는 것이 X -> 프로그램을 실행하기 위해 필요한 정보들을 포함
- stakc pointer: stack의 마지막 주소
1. Stack Frames
1.1. Stack
- LIFO data structure to hold local variables
- Higher Address에 위치하고, lower address를 향함
- Stack Pointer
- top of the stack을 가리킴
- stack pointer의 아랫 부분 -> garbage
- stack pointer의 윗 부분 -> local variables
- Memory -> byte addressable
- 1 bytes = 8 bits = 8 binary digits = 2 hexadecimal digits
- operations
- CPU 명령어
- Push(x)
- stack_pointer--;
- M[stack_pointer] = x;
- x = Pop()
- x = M[stack_ponter];
- stack_pointer++;
1.2. Stack Frames
- Activation Record
- 함수 하나하나에 할당이 된 Area on the stack
- On entry: stack grows -> 새로운 stack frame을 유지
- 함수를 호출할 때, 생성
- stack overflow? -> 재귀적으로 자신을 계속 호출하면서, stack frame을 새로 쌓아가다가, stack size를 넘어서면 발생
- On retrun: stack shrinks
- On entry: stack grows -> 새로운 stack frame을 유지
- Frame Pointer(FP): 현재 함수의 stack frame의 시작점을 가리킴
- 함수 호출 과정
- g가 Caller, f가 Callee
- f 호출
- 기존 FP 저장
- 현재 SP를 FP에 할당
- SP는 새로운 stack frame의 크기(N)만큼 아래로
- return
- 현재의 FP를 SP에 할당
- 저장된 FP를 FP에 복원
- 함수의 호출은 다음의 인스턴스화를 의미
- Local Variables
- Parameters
- Return Addresses
- Other temopraries
- Arguments accessed by offset from FP
- argument 1: M[ FP + a1 ]
- argument 2: M[ FP + a2 ]
- Caller Frame에 존재
- Local Variables accessed by offset from FP
- local variable 1: M[ FP - i1 ]
- local variable 2: M[ FP - i2]
- Frame 내부에 존재
- Dynamic Link(Control Link)
- FP 백업 -> caller의 stack frame을 가리킴
- current stack frame의 return 시에 복원하기 위함
- compile time 시에, caller frame의 사이즈가 고정됐다는 것을 알 수 있으면 필수 X
1.3. Stack Frame Organization
- Calling Convention
- Calling Convention
- 마이크로 프로세서 제조사는 모든 컴파일러가 사용하는 "표준" 레이아웃 방식을 지정
- ex) 매개변수는 어디에 배치되는가? 매개변수는 어떤 순서로 전달되는가?
- 모든 컴파일러가 같은 calling conventions 사용 -> 하나의 컴파일러로 다른 컴파일러로 컴파일된 함수를 호출 가능
- OS/Libraries와 상호작용에 필수적
- 마이크로 프로세서 제조사는 모든 컴파일러가 사용하는 "표준" 레이아웃 방식을 지정
2. Registers
- Registers are faster than memory
- 컴파일러는 가능한 register에 값을 저장해놔야 함
- Calling conventio
- Caller-save registers: caller가 저장해야 하는 레지스터
- callee 호출 이후 사용될 레지스터 values -> 미리 stack에 저장
- Callee function은 해당 레지스터 값들을 저장하지 않고, caller-save registers 사용
- Calle-save registers: callee가 저장해야 하는 레지스터
- Caller-save registers: caller가 저장해야 하는 레지스터
-> caller save registers, callee save registers의 저장 >> 해당 레지스터들을 callee 내부에서 자유롭게 사용 가능
- Registers가 저장하는 것들
- Parameters
- Return Values
- Intermediate results of expressions(temporaries) -> 프로그램 실행 중간 결과
- Stack Frame이 저장하는 것들
- register에 저장하기에 크기가 큰 variables
- Array variables
3. Passing Parameters
- f(a1, a2, ..., an)
- Modern calling convention
- a1, ..., ak를 registers r1, ..., rk에 저장
- 나머지 ak, ..., an을 stack에 저장
-> 나중에 해당 레지스터들을 사용할 필요가 생기면, 해당 레지스터 값들도 f함수 내부에서 push 진행될 수 있음
- C language에서는 former parameter(argument)의 주소(pointer)에 접근 가능
- pointer -> 메모리에 해당 주소값이 저장돼있다는 의미
- parameters가 레지스터로 옮겨지더라도, 주소를 위한 공간은 반드시 할당되어야 함!!
- stack frame이 사라질 때, 해당 주소값이 함께 사라질 수 있음 -> Dangling Reference 발생
- Nested Functions with Returned Function
- 현대 언어의 nested function의 경우 local variables를 heap에 저장해야 함
- ex) 함수 f(x)는 g(y)라는 함수를 반환하는데, g(y)는 x + y를 반환하는 함수이다.
- 하지만, 함수 f(x)가 종료된 시점에 x에 대한 정보가 사라지면 g(y)에서는 이를 사용할 수가 없다.
- 따라서 stack이 아닌 heap에 x를 저장하여 보존
4. Return Address
- function call을 모두 수행하고 나서, 다시 돌아가야할 명령어의 주소
- calling convention에 따라
- x86 -> on the stack
- arm -> in a register
- Callee-save register
5. Static Links
- Dynamic Link: 이런 frame의 시작점을 FP에 할당하는 방식
- Static Link
- outer function's stack frame에 접근하고자할 때 사용
728x90
반응형