레이블이 stack인 게시물을 표시합니다. 모든 게시물 표시
레이블이 stack인 게시물을 표시합니다. 모든 게시물 표시

Stack 메모리, push, pop 명령어

스택 자료구조는 LIFO(Last in First Out) 구조로 마지막에 들어간 값이 가장 먼저 나오는 구조를 갖고 있다. CPU는 PUSH, POP어셈블리어 명령어와 esp, ebp 레지스터를 이용해서 스택을 관리하고 스택에는 지역변수와 임시 데이터들이 저장된다. EBP는 스택에서 가장 낮은 바닥(bottom)의 주소를 갖고 있고 ESP 는 스택 꼭대기인 탑(top)의 주소를 갖고 있다.



PUSH 명령어는 ESP위에 값을 넣고 ESP가 새로운 값을 가리키게 만든다(그림 상 한칸 올라간다).
POP명령어는 ESP가 가리키는 값을 스택에서 빼고 ESP를 한 칸(4byte) 내린다.

PUSH 0x1010명령어가 실행되면 esp는 한 칸 위로 올라가고(주소는 4byte 감소) 그 곳에 0x1010이 들어간다.위의 그림에서 PUSH 0x1010이 실행되면 ESP는 low address가 적혀있는 곳을 가리키게 되고 그 안에는 0x1010의 값이 들어간다.

POP명령어의 operand는 한 개고 레지스터가 오게 된다. POP eax가 실행되면 ESP가 가리키고 있는 DATA가 eax에 저장되고 ESP는 한 칸(4Byte) 내려온다. 위의 그림에서 POP eax가 실행되면 DATA1 (TOP)이 eax에 저장되고 ESP는 DATA2를 가리키게 된다.
Read more

stack, prologue, leave, ret

임시 자원들을 관리하기 위하여 프로세스는 stack(쓰레드마다 stack이 생성된다.)이라는 메모리 영역을 할당받아 관리한다.
stack 자료구조는 후입선출법(LIFO)으로 나중에 들어온 데이터를 먼저 뽑아쓰는 구조로
stack 메모리는 stack자료구조를 push, pop과 esp, ebp로 구현한다.

esp는 스택의 최상단을 포인팅, ebp는 스택의 베이스를 포인팅하는 레지스터이고
push data는 stack 상단에 data를 넣고 esp를 증가시켜주고 pop reg로 esp가 가리키고 있는 data를 reg에 넣고 esp를 내려주는 명령어이다.

스택메모리에서 함수가 호출 될 때, 함수에서 빠져나올 때 마다 ebp, esp가 셋팅되는 것을 알아보자.

함수가 호출되고 지역변수를 잡은 후의 스택 메모리의 모습이다.(아래가 높은주소)




새로운 함수 호출

새로운 함수의 호출은 call func() 로 실행 될 수 있다. call func()는 push eip(RET backup) + jmp func() 와 같다. 
func() 함수가 끝난 후 돌아올 eip주소를 백업하고(RET),  func()의 기계어 코드가 있는 곳으로 eip를 이동시켜 func() 를 실행한다.

call func() 가 실행된 직후의 스택의 모습은 위의 그림에서 RET 값이 셋팅되고 esp 가 RET를 가리키고 있는 모습이다. ebp는 func()을 호출한 콜러의 ebp를 가리키고 있다.

이제 eip는 func()함수의 프롤로그를 수행 할 차례이다. 함수는 시작부분에 push ebp/mov ebp, esp라는 프롤로그를 갖고 있다.
프롤로그가 실행되면 push ebp로 (SFP)콜러의 ebp가 백업되고 ebp, esp가 SFP를 가리키게 된다. 이렇게 func()의 스택이 초기화 되어 func()는 스택을 독립적으로 사용할 수 있다.

변수의 전달

argv는 call을 하기 전에 스택에 argv를 push하여 func()로 전달하고 ebp+'x'로 값을 얻어쓴다.
local value는 func()의 프롤로그가 실행 된 후 sub esp, 'x'로 esp를 local value만큼 위로 올리고 esp + 'x'로 값을 얻어서 쓴다.

함수에서 콜러로 복귀

func() 함수가 모두 실행 된 후에는 func()를 호출한 콜러로 복귀를 해야한다. 스택 정리를 위해서 leave, ret을 실행 한다.
leave 는 mov esp, ebp/pop ebp로 esp를 ebp위치와 같게 내려 놓고 SFP(콜러의 ebp backup)를 ebp에 넣어 ebp를 이전 함수의 위치로 복귀 시킨다. pop명령어를 실행 하였기 
때문에 esp는 RET를 가리키고 있다. 

그 다음에는 ret(pop eip + jmp eip)가 실행된다. pop eip로 eip에는 RET(call func()의 바로 밑의 주소)이 들어가고 jmp eip로 eip는 func()가 호출된 다음의 코드를 가리키게 된다.
이렇게 되면 func()가 호출되기 이전의 스택모양과 똑같아진다!

Read more