본문 바로가기
C언어/C언어

[C언어]함수 호출을 통한 스택 메모리 이해[1](by 어셈블리어)

by Oliver_Candy 2023. 2. 21.

어셈블리어-스택메모리

 


이번 글에서는 간단한 함수 호출을 하는 코드를 어셈블리어로 보면서 스택메모리가 실제로 어떻게 변수를 쌓아가는지를 배우겠습니다. 이번글에 들어가기 전에 먼저 알아야 될 용어들은 EBP (Extended Base Pointer), ESP (Extened Stack Pointer) 스택프레임입니다.

 

 

 EBP, ESP, 스택프레임이란?

 EBP (Extended Base Pointer)는 현재 스택프레임의 첫 주소입니다.

 EBP (Extended Stack Pointer)는 영어를 보시다시피 현재 스택이 어디까지 채워져 있는지 보여주는 포인터입니다.

스택프레임 (Stack Frame)은 각 함수가 사용하는 스택 메모리 범위입니다. 스택 프레임은 보통 ebp, esp사이의 범위입니다.(하지만 esp는 움직이는 포인터이므로 함수가 다 끝났을 때 esp위치를 기준으로 합니다.) 예전 글에서도 말했듯이 스택은 큰 주소에서 작은 주소로 쌓입니다.

스택메모리-개념-정리

 

 함수 호출로 스택메모리 이해하기

int add(const int a, const int b)
{
    int res = a + b;
    return res;
}

int main(void)
{
    int a = 1;
    int b = 2;
    return add(a, b);
}

이 add() 함수를 호출하여 반환 값을 리턴하는 함수를 어셈블리어를 통하여 이해해 봅시다.

 

 

 1. 스텍 프레임 설정

스택메모리-설명-1
스택메모리-설명-1

먼저 sub전에 [mov ebp, esp]부터 보자면 이 뜻의 의미는 'esp를 esp에 맞춰라'입니다. 그림과는 다르지만 먼저 ebp와 esp는 위치가 동일한 곳을 가리킵니다. 다음 코드인 [sub esp,14h]는  esp주소를 14h만큼 빼라는 것입니다. 14h는 hex라는 의미의 16진수를 나타낸 것으로 10진수로는 20입니다. 즉, esp주소를 10진수로 20만큼 뺀 위치로 옮겨라라는 뜻으로 esp는 ebp위치에서 20 바이트 뺀 0x0073FE58 위치로 이동하게 됩니다. 혹시나 이렇게 물어보실 수 있습니다. 20바이트만큼 빼야 되는 걸 어떻게 알죠? 이는 컴파일할 때 main함수를 보고 지역변수등 이외에 것들을 모두 하면 20바이트가 필요하다고 계산이 이미 되어있어서 어셈블리어 코드에 적혀있는 겁니다.

 

 

 2. 변수 a, b 스택 메모리에 집어 넣기

스택메모리-설명-2
스택메모리-설명-2

[mov dword ptr [ebp-8],1] 코드를 설명하기 전 [mov dword ptr [ebp-4], 0]이라는 코드는 저도 정확하게는 알지 못합니다. 다만 디버그 단계에서 어셈블리어를 보고 있어서 최적화가 안 되어있다고 생각하시면 될 것 같습니다. [mov dword ptr [ebp-8],1] 코드를 보시면 ebp에서 8만큼 뺀 주소에 1이라는 값을 집어넣으라는 코드입니다. 그래서 스택 메모리를 보신다면 0x0073FE64주소에 1이 들어가 있는 것을 알 수 있습니다. [mov dword ptr [ebp-0Ch],2] 코드도 아까 전처럼 ebp주소에서 12만큼 뺀 곳에 2라는 값을 집어넣으라는 의미입니다.

 

 3. add()함수의 매개변수 값을 복사

스택메모리-설명-3
스택메모리-설명-3

코드에서 eax, ecx가 무엇인지 궁금할 것입니다. eax, ecx는 CPU에 있는 레지스터로 CPU가 가지고 있는 공간(하드웨어)으로 아시면 됩니다. 이 공간들은 eax, ebx, ecx... 등으로 나타냅니다. 그래서 [mov eax, dword ptr [ebp-0Ch], [mov ecx, dword ptr [ebp-8]] 코드는 전부 CPU레지스터에 각각 2와 1을 대입하라는 뜻입니다. [mov dword ptr [esp], ecx] , [mov dword ptr [esp+4], eax] 의미는 이제 아시겠죠? 값을 대입하라는 뜻인데, 요번에 대입되는 값은 add() 함수를 실행하기 위해서 전달되는 매개변수를 복사한다는 뜻입니다. 함수에 매개변수를 전달할 때에는 무조건 복사를 통해서 전달한다는 것을 이 그림을 통해서 이제 이해하실 수 있을 겁니다.

 

 4. call()함수 호출

스택메모리-설명-4
스택메모리-설명-4

마지막으로 [call 00011040] 함수는 이 주소로 점프하라는 뜻입니다. call이라는 명령은 push + jump 두 개를 포함된 명령어로 push라는 뜻은 'esp포인터가 가리키는 메모리 위치 다음에 있는 스택 메모리에 값을 집어넣으라'는 뜻으로 여기서는 esp메모리를 늘린 메모리에 함수를 호출하고 난 뒤에 다음으로 갈 명령어 주소 값을 대입을 하고 add() 함수로 jump 하게 됩니다. 

 

 

 

이번 글은 매우 길어서 두, 세편으로 나누어서 작성하겠습니다. 다음글은 add() 함수 어셈블리어 코드부터 시작하도록 하겠습니다.

 

 

 

댓글