게임 개발/C++

[C++] 스택 프레임 - 2. 적재 순서 메모리 확인

유행성바코드 2025. 3. 3. 23:15

목차

  • 01. Intro
  • 02. 스택 프레임
    • 정의 및 구조 복습
    • 적재 순서 메모리 확인
    • 구조체 매개 변수
  • 03. 마무리
  • 04. 연관 내용

01. Intro

오늘은 스택 프레임(Stack Frame)의 적재 순서를 메모리와 어셈블리어를 통해 직접 확인해 보겠습니다.

 


02. 스택 프레임

스택 프레임을 생성할 때, 메모리로 확인하기 전에 관련 내용을 다시 한번 짚고 넘어가겠습니다.

 

정의 및 구조 복습

함수를 호출하고 종료하는 과정은 아래와 같습니다.

 

함수 호출 시, 스택 프레임이라는 메모리 블록이 생성됩니다.

생성된 스택 프레임은 콜 스택에 순차적으로 쌓입니다.

콜 스택은 마지막에 쌓인 스택 프레임부터 사용합니다.

함수가 종료되면, 현재 함수의 스택 프레임을 제거합니다.

그리고, 콜 스택에서도 스택 프레임이 제거되므로 제거가 된 후의 마지막 스택 프레임 즉, 이전 함수로 이동합니다.

 

스택 프레임의 내부 구조는 아래와 같습니다.

매개 변수, 반환 주소값, 지역 변수 순으로 적재됩니다.

이때, 높은 메모리 주소부터 낮은 메모리 주소 순으로 적재됩니다.

 

적재 순서 메모리로 확인

#include <iostream>

using namespace std;

void simulate(int a, int b)
{
	int m = 50;
	int n = 100;
	return;
}

int main()
{
	// 15번째 줄에 중단점 걸어주기
	simulate(5, 30);

	return 0;
}

위 코드를 바탕으로 먼저, 함수의 매개 변수가 오른쪽에서 왼쪽으로 적재되는지 확인하겠습니다.

 

simulate(5, 30)에서 중단점을 걸고 디버깅 모드에 진입합니다.

해당 상황에서 어셈블리어를 확인하면, 아래 사진과 같습니다.

먼저, 1E를 푸시하고 5를 그다음에 푸시하는 것을 확인할 수 있습니다.

1E는 16진수의 표현이므로 10진수로 변경하면, 30입니다.

 

1E를 먼저 푸시하기에 1E가 먼저 적재되고 그 위에 5가 적재됩니다.

이를 메모리에서 직접 확인해 보겠습니다.

 

먼저, 메모리 창에서 esp를 입력해 현재 스택의 최상단으로 이동합니다.

여담으로 esp(Stack Pointer)는 현재 스택의 최상단을 가리키는 레지스터입니다.

 

그리고, esp보다 작은 메모리 주소 값에 적재, 즉, 현재 빨간색 박스보다 위에 적재됩니다.

따라서, 위에서 확인합니다.

 

어셈블리어 push 1E를 하면, 그 위에 1e 값이 적재됩니다.

 

그다음인 어셈블리어 push 5를 하면, 그 위에 5 값이 적재됩니다.

 

그리고, 매개 변수 위(빨간색 박스 내의 마지막 줄)에 반환 주소값이 적재됩니다.

반환 주소값은 함수가 종료되었을 때, 복귀해야 할 주소값이 저장되어 있습니다.

그래서, ret 어셈블리 명령어를 실행하면, 해당 주소로 점프함으로써 현재 함수가 종료됩니다.

 

다시 돌아와서, 반환 주소값 위에 ebp가 저장됩니다.

 

ebp(Base Pointer)는 현재 함수의 스택 프레임에 대한 기준점을 저장하는 레지스터입니다.

esp와 달리 항상 고정된 값을 유지하고 항상 현재 실행 중인 스택 프레임의 기준점을 가리킵니다.

그래서, 함수를 새롭게 호출할 때, 이전 함수의 ebp를 스택에 저장합니다.

저장 위치는 새롭게 생성된 스택 프레임의 ebp에 저장됩니다.

즉, 새로운 스택 프레임의 ebp는 이전 함수의 ebp 주소값을 가지고 있습니다.

 

요약하면, 아래와 같은 설정 과정을 거치게 됩니다.

1. 함수 호출할 때, 호출하는 함수 매개 변수를 먼저 푸시

2. 이전 함수 리턴 주소를 그다음에 푸시

3. 이전 함수의 ebp를 스택에 푸시

4. 현재 esp 값을 새로운 ebp로 설정 ( 어셈블리어 : mov ebp, esp )

5. 현재 함수의 지역 변수를 스택에 푸시 

 

 

ebp 자체의 메모리 주소를 기준점으로 오프셋을 더하거나 빼서 매개 변수나 함수의 지역 변수에 접근을 쉽게 할 수 있습니다.

따라서, 매개 변수에 접근할 때는 예시로 [ebp + 8], [ebp + 12] 등으로 접근합니다.

반대로, 지역 변수에 접근할 때는 예시로 [ebp - 4], [ebp - 8] 등으로 접근합니다.

즉, ebp 메모리 주소에 어떠한 값을 더하거나 빼서 매개 변수 및 지역 변수에 접근할 수 있습니다.

 

예외로 [ebp + 4]는 반환 주소값이므로 위 상황에서는 사용하지 않습니다.

 

이제, simulate 함수를 실행했습니다.

ebp 위에서 simulate 함수 내에 있는 지역 변수 m의 값인 50을 적재합니다.

16진수의 32가 10진수로 변환하면, 50이 됩니다. 

 

다음으로, simulate 함수의 마지막 지역 변수인 n의 값인 100을 적재합니다.

16진수의 64가 10진수로 변환하면, 100이 됩니다.

 

함수가 종료된 후에, simulate의 지역 변수에 대한 메모리 접근을 시도했을 때, 접근을 못하는 걸 확인할 수 있습니다.

 

그런데, 메모리가 해제되었음에도 값은 남아있는 것을 확인할 수 있었습니다.

이는 새로운 스택 프레임이 생성되면, 다시 덮어써지기 때문에 성능을 위해서 별도의 초기화 과정을 거치지 않습니다.

 

 

구조체 매개 변수

#include <iostream>

using namespace std;


struct Info
{
	int x;
	int y;

	Info() : x(10), y(20) {}
};

void simulate(int a, Info b, int c)
{
	return;
}

int main()
{
	// 기본값 사용 : info.x = 10, info.y = 20
	Info info;

	simulate(5, info, 30);

	return 0;
}

 

이번에는 매개 변수에 구조체 변수가 있을 때, 어떻게 작동하는지 한 번 확인해 보겠습니다.

 

중간까지 실행한 결과, 30 위에 20의 값이 적재되는 걸 확인할 수 있었습니다.

 

매개 변수를 모두 적재한 결과, 30, 20, 10, 5의 순서대로 값이 적재되었습니다.

 

따라서, 구조체 매개 변수는 선언된 순서 밑에서부터 위로 적재되는 것을 알 수 있었습니다.

 


03. 마무리

오늘은 스택 프레임의 구조를 메모리와 어셈블리어를 통해서 확인해 봤습니다.

직접 확인하니 높은 메모리 주소에서 낮은 메모리 주소 순으로 매개 변수, 반환 주소값, ebp, 지역 변수가 적재되어 있었습니다.

스택 프레임과 관련된 내용은 오늘 글을 끝으로 마무리 짓겠습니다.

 


04. 연관 내용

  • [C++] 스택 프레임 - 1. 정의 및 구조
 

[C++] 스택 프레임 - 1. 정의 및 구조

목차01. Intro02. 스택 프레임정의콜 스택 & 스택 프레임스택 프레임 내부 구조매개 변수 적재 순서스택 오버플로우03. 마무리04. 연관 내용01. Intro오늘은 스택 프레임(Stack Frame)에 관련된 내용을 한

epidemic-barcode.tistory.com

 


 

읽어주셔서 감사합니다.

틀린 내용 지적은 언제나 환영입니다!