0. 함수 호출 규약이란
- 어떤 함수를 호출할 때 함수의 인자를 어떤 방식으로 넘겨주는가에 대한 약속
1. 스택 프레임
- 함수가 호출될 때마다 높은 주소에서 낮은 주소로 스택이 쌓이는 형태로 함수의 정보를 담고 있음
- 함수의 정보란 매개 변수, 반환값, 지역변수를 의미함
- 메모리의 스택 영역에 저장되는 정보임
- 위 사진과 같이 함수가 불릴 때 마다 함수의 정보들이 쌓이는 것을 스택 프레임이라고 함
- 스택의 자료구조 특성 상 맨 나중에 불린 함수가 먼저 정리되고 함수가 불리고 끝나고를 반복하며 이 스택프레임이 쌓였다가 정리되었다가 하는 과정이 프로그램 실행 중에 계속 일어나고 있는 것이다.
2. 메모리 오버플로우
- 사용하고자 하는 메모리 공간보다 더 사용하여 다른 메모리 공간이 덮어씌워지는 경우를 일컫음
- 주로 버퍼 오버플로우라 하는 것 같고 해킹 용어로 보임
int* pa = new int[10];
pa[11] = 20; //buffer overflow!!
- 위 코드가 간단한 예시가 될 수 있을 것 같다.
3. EBP, ESP 레지스터
- 레지스터란 CPU가 요청을 처리하는데 필요한 데이터를 일시적으로 저장해주는 기억 장치
- EBP, ESP는 스택 프레임에서 최상단 함수의 시작과 끝 주소라고 생각하면 됨
- 위 사진의 Step3에서 Func1()의 초록과 주황 사이를 EBP가 가리키고 Func2()의 초록색 부분의 최상단을 ESP가 가리킨다고 보면 된다.
- 이 때 함수가 불려있는 중엔 EBP는 변할 일이 없고 ESP는 PUSH, POP이라는 어셈블리어에 의해 위치가 계속 변하게 된다.
- 함수가 정리되게 되면 ESP는 기존 EBP의 위치를 물려받을 것이고 EBP는 이전 함수의 스택 프레임의 주소를 알게 될 것이다.
4. 함수 호출 규약
- cdecl, stdcall, fastcall, thiscall 등이 있음, 중요한 특징만 나열하고자 함
- cdecl : Caller가 StackFrame 정리 -> 가변 인자 가능, main 함수, C, C++의 함수에 따로 지정하지 않는다면 이 호출 규약을 따름
- stdcall : Callee가 StackFrame 정리 -> 가변 인자 불가능, WinAPI 프로그래밍에서 WINAPIENTRY라는 치환 구문이 __stdcall임(WinMain)
- fastcall : stdcall과 크게 다르지 않으나 인자에서 2개까지 레지스터로 전달해주어 더 빠른 처리가 가능하다고 함
- thiscall : 클래스의 멤버함수는 이 호출 규약을 따르며 클래스 내 this 포인터의 사용이 가능한 것이 이 호출규약 덕분. 기본적으론 가변인자가 불가능하다고 함.
5. 가변 파라미터 함수 구현
- #include <cstdarg>
- va_list, va_start, va_arg, va_end
- 가변인자의 주소를 알기 위한 va_list 변수 -> va_list arg_pointer;
- va_list 변수의 주소를 찾아주는 va_start -> va_start(arg_pointer, 고정인자의 마지막 변수);
- 실제 가변인자들을 불러오는 va_arg -> int num = va_arg(arg_pointer, int);
- int 크기만큼 포인터 주소를 옮겨가며 값을 읽는 것
- va_list 변수를 nullptr로 비워주는 va_end -> va_end(arg_pointer);
'C++ > 키워드 정리' 카테고리의 다른 글
키워드 정리 [8] - 정수, 실수 (1) | 2023.12.01 |
---|---|
키워드 정리 [7] - 컴파일 (1) | 2023.12.01 |
키워드 정리 [5] - 동적 할당 (1) | 2023.12.01 |
키워드 정리 [4] - 구조체 (1) | 2023.12.01 |
키워드 정리 [3] - 매크로 (1) | 2023.12.01 |