Stack Operations
stack data structure
- 대표적인 LIFO 구조이다.
- 그동안 알고있던 건 어플리케이션의 스택이고 여기서 다루는 스택은 runtime 스택이다.
런타임 스택
- CPU의 하드웨어에서 직접 지원된다.
- 프로시저를 호출하고 프로시저를 반환하는 매커니즘에서 필수적인 부분이다.
- 메모리의 한 블럭을 스택으로 사용
- 메모리의 일정 부분을 스택으로 사용한다. (스택 세그먼트 있다.)
- 즉 시스템 수준에서 작동해서 서브루틴 호출을 처리한다.
프로시저란
서브루틴을 프로시저라고 부른다.
서브루틴 : 명령어들이 모여있는 메모리 블록 즉 쉽게 생각하면 원시적인 수준의 함수이다.
- 런타임 스택은 서브루틴 호출을 처리한다.
1. Runtime Stack (32-Bit Mode)
- CPU에서 ESP(스택포인터)레지스터를 사용해서 직접적으로 관리를 하는 메모리 배열이다.
- 따라서 ESP를 직접 조작하는 경우는 거의 없다.
- CALL, RET, PUSH, and POP 같은 간접 명령어로 수행한다.
- ESP레지스터는 32비트 오프셋을 유지한다.
- ESP레지스터는 스택의 TOP을 가리키고 있다.
- 아래 그림에서 스택 포인터 값이 감소하면 스택의 맨위가 아래로 이동한다.
1-1. Push Operation
- 스택 포인터 4를 감소시킨다.
- 스택 포인터가 가리키는 스택 내 위치로 값을 복사한다.
- 런타임 스택은 높은 주소에서 낮은 주소로 메모리에서 아래쪽으로 증가합니다.(이 그림은 top이 아래쪽이다.)
1-2. Pop Operation
- 스택에서 값을 제거합니다.
- 스택 포인터가 스택에서 다음으로 높은 위치를 가리키도록 증가한다.
1-3 stack aplication
- 스택은 레지스터를 여러 용도로 사용할 때 편리하게 임시 저장공간으로 활용할 수 있다. (수정 한 후 pop하면 원래 값으로 복원할 수 있기 때문)
- CALL명령이 실행되면(서브루틴 호출) CPU는 현재 서브루틴의 리턴 주소(복귀 주소)를 스택에 저장한다.
- 서브루틴을 호출 할 때 함수 인자를 스택에 넣어서 전달한다.
- 스택은 서브루틴 내부의 로컬 변수를 위한 임시 저장소를 제공한다.
PUSH Instruction(지침)
ESP 감소
– 16비트 피연산자는 ESP를 2만큼 감소시킵니다.
– 32비트 피연산자는 ESP를 4만큼 감소시킵니다.
그 이후 소스 피연산자를 스택에 복사한다.
PUSH reg/mem16
PUSH reg/mem32
PUSH imm32
pop Instruction(지침)
- ESP가 가리키는 스택 요소의 내용을 16비트 32비트 대상 피연산자로 복사한다.
- 그 후 ESP를 증가시킨다. (16비트면 2 32비트면 4)
POP reg/mem16
POP reg/mem32
PUSHFD and POPFD Instructions(지침)
- PUSHFD 명령은 스택으로 32비트 EFLAGS 레지스터를 푸시합니다.
- POPFD 명령은 스택을 팝하는데 EFLAGS로 들어간다.
- MOV는 플래그를 변수에 복사하는 데 사용할 수 없으므로 플래그를 저장하는 가장 좋은 방법은 PUSHFD입니다.
- 나중에 이전 값으로 복원할 수 있도록 플래그의 백업 복사본을 만드는 것이 유용한 경우가 있습니다.
- 종종 PUSHFD 및 POPFD 내에 코드 블록을 묶습니다.
pushfd ;sace the flags
;
;any squejce of statement here
;
popfd ; restore the flag
- POPFD 명령을 건너뛰는지 아닌지 확인 할 필요가 있다!(PUSH했으면 pop하는게 맞다!! )
- 플래그 레지스터에 대한 mov연산이 없기 떄문에 활용이 가능하다.
PUSHAD, PUSHA, POPAD, and POPA
D가 붙은게 32비트 버전 D가 안 붙은게 이전버전이다.
- 스택에 있는 모든 32비트 범용 레지스터를 다음과 같은 순서로 푸쉬한다.
- EAX, ECX, EDX, EBX, ESP (value before executing PUSHAD), EBP, ESI, and EDI
- 일반적으로 프뢰시저를 시작할 떄 PUSHAD명령을 수행한다.
16비트 버전
- PUSHA는 스택의 16비트 범용 레지스터를 다음 순서로 푸시합니다:
- AX, CX, DX, BX, SP, BP, SI, DI
- POPA 명령은 동일한 레지스터를 역순으로 팝합니다.
- 16비트 모드에서 프로그래밍할 때만 PUSHA 및 POPA를 사용해야 합니다.
여러 32비트 레지스터를 수정하는 프로시저를 작성하는 경우 프로시저의 시작 부분에는 PUSHAD를, 끝 부분에는 POPAD를 사용하여 레지스터를 저장 및 복원합니다..!
다만 예외적으로 하나 이상의 레지스터에 결과를 반환하는 프로시저는 PUSHA및 PUSHAD를 사용해서는 안됩니다.
- 다음 ReadValue프로시저가 EAX 의 정수를 반환한다고 가정할 때..!
- POPAD호출은 EAX 반환값을 덮어쓴다.
문자열 반전 예시코드
Uploaded by N2T
728x90
'CSE > system programing' 카테고리의 다른 글
[시스템 프로그래밍 7-3] Irvine32 Library 정리 (0) | 2023.04.28 |
---|---|
[시스템 프로그래밍 7-2] 프로시저(Procedures)와 USER OPERATOR (0) | 2023.04.28 |
[시스템 프로그래밍 6-3] 어셈블리어 JMP와 LOOP명령어 (0) | 2023.04.06 |
[시스템 프로그래밍 6-2] 어셈블리어 데이터 관련 연산자와 간접 주소방식 (0) | 2023.04.06 |
[시스템 프로그래밍 6 -1] 어셈블리어 더하기 빼기 연산과 그에 따른 flag 세팅 (0) | 2023.04.06 |