Stack 메모리

스택(Stack)은 컴퓨터 자료 구조의 하나로

접시가 쌓여있는 모양을 스택이라고 하는데

쌓을 때는 밑에서 하나씩 올라가지만

꺼낼 때는 위에서 하나씩 가져가는

그런 형태의 자료구조입니다.

스택 자료 구조 NASM

이 직관적인 자료형은 이미

모두가 사용하고 있습니다.

 

웹브라우저의 뒤로가기 기능은

흔한 스택구조의 예시입니다.

인터넷을 서핑하면 링크를 클릭하여

계속 새로운 페이지로 들어갑니다.

예를 들어 사용자가 다음과 같이

웹서핑을 하고 있습니다.

 

네이버 -> 블로그 -> 커뮤니티 -> 웹사이트

 

stack 은 push 와 pop 으로만 자료를 이동합니다.

 

push 네이버

push 블로그

push 커뮤니티

 

현재 위치인 웹사이트에서

바로 전으로 돌아가고 싶다면

 

pop 커뮤니티

 

커뮤니티로 돌아갑니다.

 

pop 블로그

pop 네이버

 

까지 하면 네이버가 시작점이니까

돌아갈 곳이 없습니다.

 

 

물론 브라우저에는 앞으로 가는 기능도

있고 검색기능도 있지만 기본은 스택의

방식으로 작동합니다. 스택이 직관적인건

사람의 사고방식과 관련이 있는데요.

 

인간은 망각의 동물이라서 시간이 지날 수록

기억이 계속 소실됩니다. 저녁이 되면

아침에 뭘 먹었는지 기억이 잘 안납니다.

점심에 먹은 것은 아침밥보다는 기억이 더 잘 납니다.

 

사람은 바로 직전의 일을 그 전보다

잘 기억하기 때문에 오래전의 기억을

꺼내기 위해서는 '기억을 더듬어 찾는다'고 합니다.

스택 구조로 기억을 거슬러 올라갑니다.

 

*이제 컴퓨터로 돌아와서...

 

CPU에는 스택 포인터를 위한 레지스터가 있습니다. (rsp)

 

rsp 레지스터는 스택의 top(가장 최근의 값) 주소가

저장되어 있는데 push와 pop 명령어로 조작합니다.

 

사용법은 간단합니다.

 

push 값

pop 레지스터

 

입니다.

 

pop은 레지스터에 값을 꺼내옵니다.

그냥 top에 있는 값을 확인만 하려면

peek을 합니다. (peek - 엿보다)

 

어셈블리어는 원초적인 코드라서

 

mov 레지스터, [rsp]

(rsp는 주소이므로 [ ] 을 씌워서 값을 가져옴)

 

이런 식으로 peek 할 수 있습니다.

 

다음 코드는 스택에 push, pop, peek 하는 예제입니다.

 

section .data
    text1: db 10, "[stack : push, pop, peek]", 10
    text1_L: equ $-text1

    SYS_write    equ  1
    FD_write     equ  1

    EXIT_SUCESS  equ  0
    SYS_exit     equ 60

    digit db 0, 10

section .text
    global _start

_start:
    call _printText1

    ;stack push, pop, peek

    push 7
    push 5
    push 9

    pop rax
    call _printRAXDigit

    pop rax
    call _printRAXDigit

    mov rax, [rsp] ;peek
    call _printRAXDigit

    pop rax
    call _printRAXDigit

;terminate program

_last:
    mov rax, SYS_exit
    mov rdi, EXIT_SUCESS
    syscall

_printText1:
    mov rax, SYS_write ;syscall id 1 ->sys_write
    mov rdi, FD_write ;file descriptor stdout
    mov rsi, text1 ;hello world text
    mov rdx, text1_L ;byte length
    syscall
    ret ;return to where it called

_printRAXDigit:
    add rax, 48
    mov [digit], al ;write a byte
    mov rax, SYS_write
    mov rdi, FD_write
    mov rsi, digit
    mov rdx, 2
    syscall
    ret
[실행결과]

[stack : push, pop, peek]
9
5
7
7

 

push 한 값을 pop으로 찾아온다는

것은 어렵지 않을 겁니다.

peek (mov rax, [rsp])를 해도 아직

스택에 값은 남아있으니 스택을

비우기 위해서는 pop을 끝까지 해줍니다.

 

stack은 하나씩 값을 넣고 빼기 때문에

push와 pop은 포인터 연산입니다.

 

_printRAXDigit

0부터 9까지 출력하기 위한 서브루틴입니다.

 

숫자를 출력하는 것은 Hello World 에서

문자열을 출력하는 것과 또 다릅니다.

간단하게 사용할 수 있는 서브루틴입니다.

 

section .data
    digit db 0, 10

 

_printRAXDigit:
    add rax, 48
    mov [digit], al ;write a byte
    mov rax, SYS_write
    mov rdi, FD_write
    mov rsi, digit
    mov rdx, 2
    syscall
    ret

 

48의 아스키 코드는 0 입니다.

즉 48이 0, 49가 1, 50이 2...

해서 0부터 9까지 출력할 수 있습니다.

 

mov [digit], al 은 digit에 al

즉 1바이트를 씁니다. (48)

그 다음은 시스템콜로 숫자에

대응하는 아스키코드를 출력합니다.

 

두자리수 이상 출력하려면 별도로

서브루틴을 만들어야 하는데

그건 복잡하니까 간단한 코드로

작성해 봤습니다.

 

x86 64 CPU Register 기초 - NASM x86_64 어셈블리어 3

 

x86 64 CPU Register 기초 - NASM x86_64 어셈블리어 3

CPU Register CPU에는 레지스터라고 불리는 특수한 메모리가 있습니다. 컴퓨터에 메모리가 있는 것은 누구나 잘 아는 사실입니다. 메모리라고 판매를 하기 때문이지요. CPU는 메모리에 값을 넣고 계

digiconfactory.tistory.com

 

공유하기

facebook twitter kakaoTalk kakaostory naver band