외로운 Nova의 작업실

Assembly 언어 공부 - 21(Runtime Stack의 사용) 본문

Programming/Assembly

Assembly 언어 공부 - 21(Runtime Stack의 사용)

Nova_ 2022. 8. 23. 12:56

안녕하세요, 이번 시간에는 Runtime Stack(실행시간 스택)을 사용하는 방법에대해서 알아보겠습니다.

 

- Runtime Stack

Runtime Stack은 스택 포인터 레지스터라고 하는 ESP 레지스터를 이용하여 CPU가 직접 관리하는 메모리 배열입니다. ESP 레지스터에는 스택에 있는 어떤 위치에 대한 32비트 오프셋을 저장합니다. ESP를 직접 조작하는 일은 거의 없으며, CALL, RET, PUSH, POP 과같은 명령어를 사용하여 간접적으로 수정됩니다.

 

- Runtime Stack의 구조

자료구조를 배우셨다면 잘 알듯이 LIFO 구조를 가지고 있습니다. 마지막에 넣은걸 먼저 빼내야 처음에 넣었던 것을 뺄 수가 있죠. 다만, 시스템적으로보자면 Runtime Stack은 큰 숫자의 주소를 먼저 사용하고 낮은 숫자의 주소를 나중에 사용합니다. 

 

- PUSH

PUSH 명령어는 먼저 ESP를 감소시키고 다음에 소스 피연산자를 스택에 복사합니다. 피연산자가 16비트면 2씩, 32비트이면 4씩 감소시킵니다. 다만, 32비트 모드에서는 항상 32비트 피연산자를 주어야합니다.

 

- POP

POP 명령어는 먼저 ESP가 가리키는 스택의 원소의 내용을 피연산자로 복사한 다음에 ESP를 증가시킵니다. 

 

- PUSHFD 와 POPFD

PUSHFD 명령어는 EFLAGS(모든 플래그) 레지스터를 스택에 푸쉬하고 POPFD 명령어는 스택을 EFLAGS 로 팝합니다. 프로그램을 실행할때 나중에 플래그를 이전 값으로 복원할 수 있도록 플래그를 스택에 백업해놓았다가 나중에 pop하여 다시 복원할 수 있습니다. 종종 한 블록의 코드를 PUSHFD 와 POPFD 사이에 넣습니다.

 

- PUSHAD, POPAD 와 PUSHA, POPA

PUSHAD 명령어는 32비트 범용 레지스터를 EAX, ECX, EDX, EBX, ESP(명령어 실행 이전 값),ㅡ EBP, ESI, EDI 의 순으로 스택에 푸쉬합니다. POPAD 명령어는 같은 레지스터들을 반대 순서로 스택에서 팝합니다. PUSHA 명령어는 16비트 범용 레지스터들 AX, CX, DX, BX, S{, BP, SI, DI 순으로 스택에 푸쉬합니다. POPA 명령어는 같은 레지스터들을 반대 순서로 팝합니다. 프로그램을 실행할때 모든 레지스터의 값들을 스택에 백업해놓았다가 나중에 pop하여 다시 복원할 수 있습니다. 종종 한 블록의 코드를 PUSHAD와 POPAD 사이에 넣곤합니다. 단, POPAD를 하게되면 이전에 레지스터의 값들은 덮어씌워져서 사라집니다.

 

- Stack 예제 프로그램

Stack을 사용하여 기존에 있는 문자열을 거꾸로 저장해보도록 하겠습니다.

include 	c:\assembly\irvine32.inc
includelib  c:\assembly\irvine32.lib
includelib  c:\assembly\kernel32.lib
includelib  c:\assembly\user32.lib


.data
string BYTE "hello nova world", 0
lenString = ($ - string) - 1

       
.code
main PROC

    mov esi, 0
    mov ecx, lenString

L1: movzx eax, string[esi]
    push eax
    inc esi
    Loop L1

    mov esi, 0
    mov ecx, lenString

L2: pop eax
    mov string[esi], al
    inc esi
    Loop L2

    mov edx, OFFSET string
    call WriteString
    call Crlf


    exit

main ENDP

END main

위 코드에서 주의해야할 점은 문자하나하나는 BYTE 크기 이기때문에 movzx 명령어를 사용하여 EAX에 32비트로 저장하고 32비트로 push 해줘야하는 것입니다. 또한 pop할때도 32비트로 나오기때문에 실질적인 문자가 저장된 al부분만 string 배열에 저장하는 부분도 주의해야합니다. 위 코드를 실행시켜보겠습니다.

문자열이 역순으로 배열 되는 것을 확인할 수 있습니다.

Comments