스택

스택은 뭘까요? 스택은 컴퓨터 중앙 처리 장치인 CPU에서 기본적으로 사용되는 데이터 구조로, 호출된 함수에서 필요한 문자열 값이나 연산을 위한 값을 저장하는데 사용되는 공간입니다. 그리고 보통 스택은 아래와 같은 상황에서 사용됩니다.

  • 함수 호출의 리턴(복귀)값을 저장할 때
  • 파라미터 값을 저장할 때
  • 로컬 변수를 저장할 때
  • 컨텍스트 전환(스레드 스위칭)와 같은 상황으로 인해 레지스터 내용을 저장할 때

    스택의 구조

스택에서 중요한 부분은 “스택은 레지스터를 사용한다“는 것인데요. 이유는 CPU가 레지스터를 접근한다고 앞서 애기 드렸습니다. 그럼 레지스터의 값들은 어디서 가져오는 것이냐 하면 바로 스택에서 가져오게 되는 것입니다.

하지만 어디서부터 스택을 공부해야 할 지 막막할 것인데, 저자 생각하기에 가장 먼저 해야 할 일은 스택의 전체적인 구조를 파악 것이 우선입니다. 그럼 다음은 실행파일의 어셈블리 내용입니다. 여러분은 어떤 내용인지 알 수 있을까요?

[codesyntax lang=”asm”]

[/codesyntax]

자 스택의 구조인 “선입후출”의 의미로만 알 수 있을까요?

이 의미만으로는 아무것도 알 수가 없습니다. 따라서 먼저 큰 단위로 나눠서 볼 필요가 있습니다.

스택의 내용은 크게 아래와 같이 구분할 수 있습니다.

함수 도입부

함수 코드

함수 종결부

그러다 면 함수 도입부를 확인해 보도록 하겠습니다.

[codesyntax lang=”asm”]

[/codesyntax]

양이 많죠? 위 부분이 함수 도입부 인데, 함수 도입부에서 하는 일은 함수를 저장할 공간을 할당하고, 기존 포인터 위치를 기억하는 게 주된 목적이라고 보시면 됩니다. 이 부분에서 ebp에 대해 알아 보도록 하죠. ebp는 알아두어야 할 내용이 항상 주어진 프레임의 베이스 포인터(Base Pointer)를 포함한다고 생각하시면 됩니다.

그럼 아래내용은 무엇을 뜻하는 것일까요?

[codesyntax lang=”asm”]

[/codesyntax]

Push 명령을 통해 ebp를 집어넣으라는 명령으로, Stack에 자료를 집어넣을 때 사용하는 것입니다.

쉽게 말해 ebp를 집어넣으라는 뜻이지요

그래서 mov 명령으로 esp 값(Stack Pointer)을 ebp에 저장하라는 명령이 나오게됩니다.

esp 는 현재 스택 포인터 값으로, 이 포인터 위치는 항상 변하게 되므로, 항상 호출 이전의 원래 상태로 복귀됨을 보장하여야하는 메모리 구조상 esp의 복귀 주소를 사용할수 없기 때문에 ebp를 통해 복귀할 수 있는 주소를 저장하게 됩니다. (이 행동의 거희 모든 스택의 기본 동작으로 들어가 있습니다.)

mov edi,edi는 긴급 패치를 위해 사용하는데 대부분 nop(no operation)으로 상태가 됩니다. 가용성 측면으로 비사용시간을 줄이기위해 필수적으로 사용하게 됩니다. 이는 나중에 jmp 코드를 이용하기 위해 넣어 둔것이라고 생각하시면 됩니다.

자 그럼 도입부분으로 프레임의 베이스 포인터 위치를 ebp에 저장하여 프레임 복귀위치를 저장하였습니다.

이제 다음 스택을 보도록 하겠습니다.

[codesyntax lang=”asm”]

[/codesyntax]

esp, 14h가 의미하는건 14h를 10진수로 변환해 보면, 20바이트가 되며, sub는 빼는것으로, 20바이트 만큼 공간을 생성하도록 되어 있습니다.

왜 이렇게 공간을 생성하는게 빼기를 하였을까요?

메모리의 저장 위치를 잘 보시면 저장 위치의 값이 감소하도록 되어 있습니다.

즉 밑으로 갈수록 값이 감소하고 있는것이지요

그래서 아래 공간은 빼기를 통해 확보하게 됩니다.

그 렇게 확보한 공간에 ebp(베이스 포인터)의 위치 값을 이용하여 (베이스 포인터는 절대 위치 값처럼 그 프레임 내에서는 변화하지 않기 때문에 변수 저장과 같은 절대 위치가 필요한 값 저장에 사용하게 됩니다.)스택기반 지역 변수를 초기화 하게 됩니다.

그 내용이

[codesyntax lang=”asm”]

[/codesyntax]

위 부분이 되겠습니다.

그리고 포인터 전달 명령인 lea를 통해 인자를 스택에 저장 합니다.

[codesyntax lang=”asm”]

[/codesyntax]

이렇게 지역 변수를 다 저장하고 나면, Call 명령을 통해 해당 변수를 사용하게 됩니다.

그리고 수행을 마치고 마지막에 esp에 처음 저장한 ebp를 대입하여, 복귀하고, 해당 프레임을 빠져 나오게 됩니다.

[codesyntax lang=”asm”]

[/codesyntax]

이렇게 하나하나의 프레임의 복귀 주소를 저장하고 변수를 저장 후 Call을 통해 해당 명령을 수행하는 구조가 메모리의 기본 구조가 되겠습니다.

레지스터에 대해서는 인텔에서 제공하는 Intel® 64 and IA-32 Architectures Software Developer’s Manual을 확인하는 것도 필수 입니다. CPU와 밀접한 만큼 여기에서 얘기한 것보다 많은 내용을 담고 있거든요.

Facebook Comments

Leave A Reply

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.