스택프레임
- 프로그래밍/프로그래밍일반
- 2011. 3. 20. 22:10
스택프레임: 함수가 호출될 떄 스택에는 함수로 전달되는 인수, 실행을 마치고 돌아올 복귀 번지, 지역변수 등의 정보들이
저장된다. 스택에 저장되는 함수의 호출 정보를 스택 프레임이라고한다.
이며,이는 함수를 호출하게 될 시 이용되지요.
다음 소스를 보도록 하죠.
void function() {} void main() {
function(); } |
당연히 main 함수 입장에서는 function 함수의 위치를 알 수 있겠죠. function 함수의 위치는 컴파일 당시에 지정이 되니깐요
하지만, function 함수 입장에서는 자신이 돌아갈 위치를 알 수 없습니다.
function 함수가 끝나면 스택 영역에 저장된 main함수로의 복귀 주소를 참고하여 다시 돌아오죠.
사실 그림이 없어도 위 내용은 어느 정도 이해가 될 거라고 생각합니다.
그럼 다음 소스를 보도록 하죠.
void Function1() { int b = 3; //2 Function2(); //3 } void Function2() { int c = 4; //4 } void main() { Function1(); //1 } |
하는 일은 설명 안해도 쉽게 이해할 수 있는 정도입니다. 그럼 주석으로 번호를 매긴 시점의 스택 상황을 그림으로 보도록 합시다.
참고로 ESP는 포인터 레지스터 중 하나이며 32비트 Stack Pointer를 나타냅니다. 현재 스택 영역에서 가리키고 있는 위치를 기억하고 있지요. 따라서 스택 공간에 데이터가 하나씩 추가될 때마다, ESP 역시 4바이트씩 증가하게 됩니다. 그리곤 스택에서 다시 데이터를 가져오면서 스택에 존재하는 데이터는 제거할 필요없이 ESP 위치를 4바이트씩 감소만 시키면 됩니다.
위 사진은 Function1, Function2를 거친 후, 다시금 main함수로 돌아왔을 당시의 스택 영역의 모습입니다. 기록된 데이터는 여전히 남아있지만 ESP의 위치는 다시 MAIN의 복귀 주소로 돌아왔지요.
여기까지 해서, 우리는 동에번쩍 서에번쩍 함수에서 함수로 이동이 가능한 이유를 내부적으로 살펴보았습니다.
그럼 함수에서 반환값은 어떻게 전달될까요? 이는, EAX 범용 레지스터에 기록하여 반환값을 가져옵니다. 64비트 반환값 같은 경우는 EAX와 EDX를 사용하죠.
그럼, 질문 하나 더, 함수 호출 시 인자로 전달되는 데이터는 어떻게 되나?
void function1( int a, int b ) { int c = 5; } void main() { function1( 3, 2 ); } |
아, 사실 컴파일 시 생성된 어셈블리 언어를 보면 다음과 같은 부분이 있습니다.
function1: push ebp mov ebp, esp |
스택 프레임의 원리에 있어서 함수 진입 시에 스택 포인터를 ebp( 32비트 Base Pointer )에 따로 저장하는 것이죠. 그 이유는 무엇일까요?
ebp는 디버깅 시 유용히 사용하기 위한 것이죠.
void function( char* p ) { p = ‘A’; } void main() { function( 0 ); } |
위 소스를 보면 p = ‘A’ 시점에서 에러가 발생하겠죠. 에러가 발생하는 시점의 스택의 구조입니다.
마치 연결 리스트와 같은 방식으로 EBP를 추적해 나가면 함수 호출 시점들을 추적해 나갈 수 있으며 최초 EBP + 0X04 를 통해 최초 MAIN 함수로까지 돌아갈 수 있지요.
이상 스택 프레임에 대해서 간략히 소개해 보았습니다. 이해가 안되시면 정덕영 저서의 윈도우즈 구조와 원리 (한빛 미디어) 책을 추천합니다.
- 참고 : 윈도우즈 구조와 원리(한빛미디어) -
- 출저 : http://hermet.pe.kr/56227646
혼연에도 아주 자세히 나와있다.
함수 고급->호출규악->스택프레임
[출처] 스택 프레임 ( Stack Frame )|작성자 Hermet
'프로그래밍/프로그래밍일반' 관련 글
프로그래밍 에러 종류-(런타임에러, 컴파일타임에러,논리에러)
2011.03.24
Debug 하는법 Tip
2011.03.17
인자 vs 매개변수 차이점
2011.03.16