이번엔 Stack의 구조와 Stack Frame Pointer에 대해 알아보겠습니다.

 

Stack이란?

Stack이란 RAM내의 영역 중 하나로

프로그램에서 함수가 호출될 때 필요한 지역변수와 매개변수가 저장되는 영역입니다.

또 Stack은 후입선출(Last In First Out)구조이기 때문에 데이터 저장시 높은 주소에서 낮은 주소방향으로 데이터를 저장하게 됩니다.


Stack의 구조

Stack은 기본적으로 저장공간이기 때문에 데이터를 담을 수 있는 상자가 쭉 늘어서 있는 창고라고 생각하면 됩니다.

 

그럼 이 Stack에 우리의 컴퓨터는 어떤 방식으로 데이터를 저장하는걸까요?

이해를 위해서 예시를 하나 보도록 하겠습니다.

main(){

  int A = sum(1,2)

  return A

}

sum(x,y){

   return x+y

}

위와 같은 단순한 코드하나를 만들어 봤습니다. 

 

우리가 이 코드로 만든 프로그램을 돌릴때 Stack에선 데이터를 어떻게 처리하는지 보겠습니다.


Stack의 구조

함수가 호출될 때 Stack엔 매개변수, 반환 주소값, 지역변수 이렇게 3가지의 데이터가 들어갑니다.

 

main()함수 실행시

  1. main()함수엔 매개변수가 없어 반환 주소값부터 들어가게 됩니다.
  2. 가장 아래(높은)주소부터 RET(반환 주소값), RBP(main()함수 스택 프레임의 시작점), 변수 c, 버퍼(지역변수) 이렇게 채워 가는걸 볼 수 있습니다.

 

위와 같은 함수의 호출 정보를 스택 프레임(Stack Frame) 이라고 합니다.

 

sum()함수 실행시

  1. sum()함수는 main()함수 안에서 호출되기 때문에
  2. sum()함수를 호출하게 되면 main()함수의 스택 프레임위에 다시 sum()함수의 스택 프레임을 쌓게 됩니다.
  3. sum()함수엔 매개변수가 있어 매개변수 x, y를 먼저 쌓아주는 모습을 볼 수 있습니다.

 


스택 프레임 포인터(Stack Frame Pointer)

이제 Stack이 어떤식으로 데이터를 저장하는지 알게됐습니다.

그럼 저걸 어떻게 사용해서 프로그램을 돌리는 걸까요?

 

CPU내에는 레지스터라고 하는 아주 작은 값만을 담을 수 있는(하지만 처리속도가 매우 빠른)  메모리가 있습니다.

CPU는 이 레지스터와 RAM에 저장되어있는 값들을 이용하여 프로그램을 돌립니다.

Stack의 데이터들을 이용할때도 이 레지스터들을 이용하게됩니다.

 

레지스터는 여러가지 종류가 있지만 Stack에 있는 데이터를 다룰 때 사용하는 레지스터는 SP, FP 레지스터입니다.

 

SP(Stack Pointer) 레지스터 : 다음 데이터가 저장될 스택의 주소를 담고 있는 레지스터

 

FP(Frame Pointer) 레지스터 : SP레지스터가 돌아갈 주소(함수 호출 전)를 담고있는 레지스터

 

SP레지스터는 함수 호출 중 데이터가 저장될 스택의 주소를 가리킵니다. CPU가 SP가 가리키고 있는 스택에 값을 넣고 나면 SP레지스터는 그 위의 주소를 가리키게 변경됩니다.

 

FP레지스터는 함수 호출 이전에 SP레지스터가 가리키고 있던 주소를 담고있게됩니다.

 

함수 호출이 끝난 후 SP레지스터는 FP레지스터에 쓰여져있는 주소를 참고하여 함수를 호출하기 이전의 주소로 돌아가게됩니다.

 

하지만 함수 호출을 여러번 하게 될 경우 FP레지스터의 값이 계속 바뀌기 때문에 스택에 FP레지스터의 값을 저장해 놓음으로써 스택 프레임간의 경계정보를 저장합니다.

'Security > Pwnable' 카테고리의 다른 글

메모리 구조  (1) 2023.03.29

메모리 구조에 대해 이야기하기 전 프로그램의 실행순서를 알아보겠습니다.

프로그램이 실행되는 순서(Free space는  heap 또는 stack영역에 데이터가 할당되면 사용되는 곳입니다.)

 

 

메모리는 크게 4가지 영역으로 나눌 수 있습니다.

  • Code/Text 영역
  • Data 영역
  • Heap 영역
  • Stack 영역

Code/Text 영역

프로그램의 소스코드가 저장되는 영역, 기계어 형태로 저장

 

Code영역 또는 Text영역이라고도 부릅니다.

 

CPU는 Code영역에 저장된 명령어들을 하나씩 가져가 실행합니다.

 

Code영역은 프로그램이 시작하고 종료될 때까지 메모리에 계속 남아있습니다.

Data 영역

전역변수와 static변수가 할당되는 영역

 

main함수 전에 선언되어 프로그램 시작과 동시에 할당되고 프로그램이 종료하면 메모리에서 소멸됩니다.

 

Data 영역은 Rodata, BSS, Data 3가지 영역으로 나뉩니다.

 

Rodata(Read Only data)영역은 읽기 전용 data들이 들어갑니다.

주로 상수, 상수형 문자열 등의 값이 들어갑니다.

읽기 전용 영역이기 때문에 쓰는것은 불가능합니다.

 

Data영역과 BSS영역

data영역과 bss영역은 둘다 전역 변수를 저장하는건 동일합니다.

정적변수(static)도 이 영역에 저장됩니다.

data영역과 bss영역의 차이는 값이 초기화 되어있는가 되어있지 않은가의 차이입니다.

data영역은 초기화 된 변수, bss영역은 초기화 하기 전의 변수를 저장합니다.

이 영역들은 읽기 쓰기 모두 가능합니다.

 

Heap 영역

동적으로 선언된 변수가 할당되는 영역

 

메모리 위쪽 주소부터 할당되는 선입선출(FIFO) 구조

 

런타임 시 크기가 결정

 

프로그래머가 원하는 시점에 변수를 할당하고 소멸 가능하도록 하는 영역

 

사용하고 난 후 메모리 해제를 해주지 않으면 memory leak이 발생하기 때문에 반드시 메모리 해제를 해줘야 합니다.

 

 

Stack 영역

함수 호출 시 생성되는 지역변수와 매개변수가 저장되는 영역

 

메모리 아래쪽 주소부터 할당되는 후입선출(LIFO) 구조

 

컴파일 타임에 크기가 결정

 

함수의 호출과 함께 할당되며 함수의 호출이 완료(종료)되면 소멸합니다.

 

stack영역에 저장되는 함수의 호출 정보를 스택 프레임(Stack Frame)이라고 합니다.

 

오버 플로우(Overflow)

오버플로우란, 한정된 메모리 공간이 부족하여 메모리 내의 데이터가 넘쳐 흐르는 현상입니다.

오버플로우

Heap Overflow

Heap이 위에서부터 주소를 채워 내려오다가 Stack영역을 침범하는 경우

Stack Overflow

Stack이 아래에서부터 주소를 채워 올라가다가 Heap영역을 침범하는 경우

'Security > Pwnable' 카테고리의 다른 글

Stack의 구조와 Stack Frame Pointer  (0) 2023.04.01

+ Recent posts