OS마다 구현은 다르겠지만, 본 포스팅에서는 IA32로 stack에 대해 설명한다. IA32에서 사용하는 register는 다음과 같다.
%eax 등은 data를 저장하는 데 사용된다. %esp나 %ebp는 stack의 위치를 나타낸다. %eip는 PC라고 생각하면 된다.
IA32 stack
Stack은 lower address로 grow한다. %ebp가 제일 큰 주소를 가지고 %esp가 감소하는 식으로 stack에 정보를 저장한다. (아래로 큰다. Heap은 위로 큰다.)
Push
%esp의 주소가 -4되면서 data가 저장된다. 명령어는 pushl이다
Pop
%esp의 주소가 +4되면서 가장 밑에 있던 data가 pop된다.
Procedure control flow
스택에는 function call과 그에 따른 return을 관리하는데 사용된다. call label이 실행되면, 스택에는 return address가 push되고 label로 넘어가게 된다. Return address는 call이 일어난 주소 바로 다음 instruction의 주소이다. 위의 경우에는 8048553이 RA이다. Label에서 돌아올 때는, ret을 이용해 돌아온다. ret은 스택에서 RA를 pop해 jump하는 명령어이다.
Call example
스택 %esp가 감소하고 거기에 return address가 저장되고 %eip는 label로 바뀌었다.
Return example
%esp에서 return address를 가져와 %eip에 저장하고 %esp가 감소한다. 그리고 나서 %eip로 와서 instruction을 이어서 수행한다.
Stack Frames
스택은 call chain으로 이루어져있다. 이를 위해 stack에서는 frame 단위로 이를 관리한다. Frame 안에는 local variable과 return address, 그리고 stack에 일시적으로 저장해 사용하던 것들에 대한 정보가 저장되어 있다. %ebp가 따로 있었던 이유가 여기서 설명된다.
Caller frame에서 새로운 call을 실행하면 %ebp가 업데이트되고 그 밑으로 local variable이나 register 값 등이 저장된다. 모든 필요한 요소가 스택에 저장되면 %esp가 업데이트된다. 또한 나중에 return을 해야하기 때문에, current stack frame에는 caller의 %ebp가 저장되어 있다.
실제 동작을 통해 이해를 돕는다. swap 함수를 생각해 보자.
call_swap()을 호출하면 %esp가 8 감소한다. swap()에서 2개의 변수를 사용하려고 하기 때문이다. 두 개의 변수가 stack에 저장되면 swap 함수를 call하게 된다. swap에서는 다음의 명령어들이 실행된다.
setup부터 보자.
- pushl을 통해서 %ebp를 스택 밑에 저장한다. 나중에 caller frame으로 돌아오기 위함이다.
- %ebp를 %esp로 주소를 변경한다.
- %ebx의 내용을 스택에 저장한다.(기존 caller frame의 register에 저장되어 있던 친구)
Body 파트에서는 다음과 같은 일이 일어난다.
- movl 8(%ebp), %edx
xp를 %edx에 저장한다. - movl 12(%ebp), %ecx
yp를 %ecx에 저장한다. - 그리고 swap의 함수 내용을 실행한다.
Finish에서는 frame을 지우고 %ebp, %esp, %eip의 내용과 원래 사용하던 데이터 %ebx를 복원한다.
'Study > Operating System' 카테고리의 다른 글
9. Advanced lock; Locks and Condition variables (2) | 2023.12.10 |
---|---|
8. Locks (0) | 2023.12.09 |
6. Threads (1) | 2023.12.08 |
5. Virtual Memory (0) | 2023.12.08 |
4. Paging (0) | 2023.12.05 |