본문 바로가기

미분류

170315 스택(STACK) 자료구조와 프롤로그, 에필로그

1. 스택(STACK)




  • LIFO(Last In First Out)을 동작원리로 하는 자료구조.
  • 스택의 특성을 이용한 작업들
- 지역변수 저장
- 매개변수 전달
- 임시 데이터 백업
- 함수호출,복귀 정보 저장

  • Top (), Pop(), Push(), isEmpty() 등의 함수로 관리
1) 스택 프레임
- 함수와는 독립적인 메모리 영역
- 함수 호출시 생성, 복귀시 삭제
- 해당 함수는 스택을 독립적으로 사용 (새로운 함수를 사용할 때 마다 스택이 새로 할당됨)

2) 동작 순서
예 ) 메인함수 → 1함수 → 2함수 → 1함수 복귀 → 메인함수 복귀
스택 프레임이 생성되고 삭제되는곳에 프롤로그와 에필로그가있다.

3) 프롤로그 & 에필로그
함수 호출시 프롤로그가 실행되고 복귀시 에필로그가 실행 되는데 위치는 대충 이곳이다.


     main(){

     (프롤로그)

             int a=1;

             int b=3;


             testf(a,b);             

            ↑ (복귀주소 ret 를 저장하고 인자값을 스택에 쌓고 testf()함수로 넘어감)

             return 0;

     (에필로그)

     }

     testf(int a, int b){

      (프롤로그)       

             int c;

             c = a + b;


             return c;

      (에필로그)   

     }



프롤로그
  1. 새로운 함수 호출시점에 스택에 ret 생성 (복귀주소)
  2. SFP(save frame pointer)  백업 생성 → EBP에 ESP값 수록(빈 스택의 모양) SFP에는 EBP의 복귀주소가 들어있음.
  3. 새로운 함수의 시작 (함수의 시작과 동시에 새로운 스택을 할당하는 모양)



#include<stdio.h>

   main(){

    int a = 10 , b = 20, c; 

    c = addVal(a,b);

    return 0;

 }

   int addval(int a, int b){

    (프롤로그 실행)

    int c; 

    c = a+b; -1

    return c; 

  

}



프롤로그가 실행 될 때의 초기 스택프레임 상태


← EBP, ESP


int a=10, b=20, c; 의 명령을 실행, abc 변수를 만들고 해당값을 저장함.

c

← ESP

20(b)


10(a)



← EBP


addVal() 함수에 (a,b) 인자를 사용하기 때문에 함수에서 인자를 사용하기 위해 인자를 쌓아줌

인자값은 LIFO의 성질을 띄는 스택구조이기 때문에 뒤의 인자값이 먼저 들어온다.

 10(a) ESP

20(b)


c


20(b)


10(a)



← EBP


addVal() 함수가 종료된후 복귀할 명령주소를 ret에 수록

함수에서 새로 스택을 사용 하기 위해 SFP 사용

SFP

←ESP, EBP

//SFP에서 EBP에 ESP의 값을 수록하여 새로운 빈스택을 생성해줌

ret

 복귀하면 다음 명령을 실행할 주소가 저장되어 있다.

 10(a) 
 20(b) 

c


20(b)


10(a)





int c의 명령을 실행 c의 변수 확보

c

← ESP (addVal() 함수가 실행되면서 int c 로 c 변수 확보)

SFP

← EBP

ret


10(a)


20(b)


c


20(b)


10(a)





④-1

c = a+b의 명령을 실행 c변수에 30이 수록됨

30

← ESP

SFP

← EBP

ret


10


20


c


20(b)


10(a)





return 값으로 c(30) 는 EAX(누산기)에 저장된다. main()함수에서 활용할 수 있다.



에필로그


함수의 동작이 마무리 되면 EBP와 ESP의 위치를 복귀 시켜야 한다.

    1. ESP에 EBP의 값을 넣어 ESP를 EBP의 위치로 내린다.
    2. SFP에 수록되 있던 EBP의 복귀주소로 EBP의 위치를 복귀시킨다.
    3. POP() 함수를 실행, ret 위치에 ESP가 위치된다.
    4. ret(POP() EIP + JMP() EIP)가 실행 ( ① POP() EIP : EIP를 ret에 위치 ② JMP() EIP : 함수호출이 끝난 후의 다음 명령을 이어간다. )


#include<stdio.h>

   main(){

    int a = 10 , b = 20, c;

    c = addVal(a,b); 

    ④

    return 0;

    (메인함수 에필로그)

 }

   int addval(int a, int b){

  

    int c;

    c = a+b;

    return c;

   ① 에필로그 실행

}


함수가 종료되면 ESP에 EBP 값을 백업한다.
SFP에 백업되있던 기존의 EBP의 위치로 EBP가 이동한다

30


SFP

← ESP , EBP (ESP에 EBP 값을 백업) 1.

ret


10


20


c


20


10



←EBP (SFP에 백업되어 있던 위치를 찾아 이동) 2.


①-1

POP() 함수 실행 하여 SFP가 나가고 ESP가 ret으로 이동

ret

← ESP

10


20


c


20


10



← EBP



ret에서  POP() EIP +JMP() EIP : EIP를 다음 실행 명령에 위치 시키고 함수호출이 끝난 후의 다음 명령을 이어간다. 기존의 스택으로 복구하는 과정에서 인자역시 제외됨

인자를 정리 할 때는 컴파일러가 변수를 기억하고 있기 때문에 복귀시에 변수를 제외하고 위에 쌓여있는 인자들은 정리해 줌

c

← ESP

20


10



← EBP


누산기의 값을 가져오는 작업이 실행된다.  에서 누산기에 저장된 리턴값을 가져온다.

30

← ESP

20


10



← EBP


EIP를 따라 다음 명령을 실행한다.

그 후 return 0; 으로 EAX에 0이 수록되고 main()함수 마지막에 에필로그 실행.



2. 실행중인 작업을 처리하는 메모리의 구성

그림출처 : <http://ehclub.co.kr/684>

'미분류' 카테고리의 다른 글

170316 어셈블리 언어  (0) 2017.03.16
170316 Caller & Callee , 함수 호출 규약  (0) 2017.03.16
170314 리눅스, 우분투 설치 및 C 소양교육  (0) 2017.03.16
170315 C (포인터, 반복문)  (0) 2017.03.16
170315 레지스터  (0) 2017.03.16