IA-32 아키텍처에서 스택(Stack)은 프로그램 실행 중에 함수 호출, 지역 변수 저장, 리턴 주소 관리 등의 역할을 담당하는 중요한 데이터 구조입니다.
스택은 LIFO(Last-In, First-Out) 방식을 사용하여, 데이터를 저장하고 꺼내는 순서가 후입선출입니다. IA-32에서 스택은 메모리의 높은 주소에서 낮은 주소 방향으로 성장합니다.
스택은 ESP(스택 포인터)와 EBP(베이스 포인터)라는 두 개의 주요 레지스터를 이용하여 관리됩니다. 이 두 레지스터는 함수 호출과 리턴 시 스택의 상태를 추적하는 중요한 역할을 합니다.
push 명령어로 데이터를 푸시할 때마다 위로 이동하고, pop 명령어로 데이터를 팝할 때마다 아래로 이동합니다.push ebp와 mov ebp, esp 명령어를 사용하여 현재 함수의 스택 프레임을 설정하고, 함수가 종료될 때는 pop ebp를 사용하여 이전 함수의 스택 프레임으로 복원합니다.스택 프레임은 함수 호출 시마다 생성되며, 함수 호출 과정에서 스택은 아래와 같은 방식으로 변합니다.
호출자의 스택에 함수 인자 푸시:
push 명령어를 통해 스택에 저장됩니다.리턴 주소 푸시:
call 명령어는 실행 시 리턴 주소를 스택에 푸시합니다. 이 주소는 함수가 종료되면 돌아갈 위치를 나타냅니다.이전 EBP 값 푸시:
EBP 값은 푸시되어 이전 함수의 스택 프레임을 추적할 수 있게 됩니다. 이를 통해 함수 호출 전 상태로 돌아갈 수 있습니다.새로운 스택 프레임 설정:
mov ebp, esp 명령어는 새로운 스택 프레임을 설정합니다. EBP는 현재 스택 포인터를 기준으로 함수 내 지역 변수를 관리합니다.지역 변수 공간 확보:
sub esp, n 명령어를 사용하여 함수 내에서 필요한 지역 변수 공간을 확보합니다. 이 공간은 함수 내에서만 사용됩니다.함수 종료 시 스택 복원:
mov esp, ebp로 ESP를 원래 상태로 복원하고, pop ebp로 이전 함수의 EBP 값을 복원하여 스택을 청소합니다.; main 함수
push 5 ; 인자 5를 스택에 푸시
call myFunction ; myFunction 함수 호출
; myFunction 함수
myFunction:
push ebp ; 이전 EBP 저장
mov ebp, esp ; EBP를 ESP로 설정하여 새로운 스택 프레임 생성
sub esp, 4 ; 지역 변수 4바이트 공간 할당
; 여기에서 5를 처리하는 코드
mov eax, [ebp+8] ; 첫 번째 인자 (5) 로드
; 함수 끝내기
mov esp, ebp ; ESP를 원래 EBP로 되돌림
pop ebp ; 이전 EBP 값 복원
ret ; 호출한 위치로 돌아가기
예시 :
main 함수에서 push 5를 사용하여 함수 인자 5를 스택에 푸시합니다.
call myFunction 명령어는 myFunction 함수로 이동하며, 리턴 주소를 스택에 푸시합니다.
myFunction 함수에서 push ebp로 이전 함수의 EBP 값을 저장하고, mov ebp, esp로 새로운 스택 프레임을 설정합니다.
sub esp, 4로 지역 변수 공간 4바이트를 확보하고, 함수 인자 5를 [ebp+8]로 로드합니다.
함수 실행 후, mov esp, ebp로 스택을 복원하고 pop ebp로 이전 함수의 EBP 값을 복원합니다.
마지막으로 ret 명령어를 사용하여 리턴 주소로 돌아가며 함수 호출이 종료됩니다.
스택 프레임 예시 (시각화)
+------------------------+
| 리턴 주소 (myFunction) | <--- 이 주소로 돌아옴
+------------------------+
| 이전 EBP 값 |
+------------------------+
| 인자 5 | <--- main 함수에서 푸시된 값
+------------------------+
| 현재 EBP | <--- myFunction의 스택 프레임 기준
+------------------------+
| 지역 변수 (4바이트) | <--- 함수 내에서 사용하는 지역 변수
+------------------------+
| ... |
+------------------------+