🤍 전 강의 25% 할인 중 🤍

2024년 상반기를 돌아보고 하반기에도 함께 성장해요!
인프런이 준비한 25% 할인 받으러 가기 >>

  • 카테고리

    질문 & 답변
  • 세부 분야

    게임 프로그래밍

  • 해결 여부

    해결됨

제가 스택 프레임을 잘 이해한 것이 맞는 걸까요?

21.12.29 21:59 작성 조회수 329

0

 디어셈블리를 보면서 한번 쭉 따라가보았는데 제가 잘 이해한 것인지 헷갈려서 정리한 것을 올려봅니다. 

 

스택프레임 순서

  1. 현재 매개변수 저장
  2. 이전 BP(주소)값 저장 : push rbp
  3. RDI 값 저장 : push rdi
  4. 현재 SP(주소)값 저장 : sub rsp
  5. 현재 BP(주소)값 저장 : lea rpb [rsp + n]
  6. 피호출자 매개변수 저장 : mov 형식 ptr [rsp + n]
  7. (피호출자 입장) 이전 BP(주소)값 저장. 5번 값과 똑같음

 

 그리고 정리를 하다보니 번외로 이해하기 너무 어렵거나 궁금한 부분들이 있어서 염치 불구하고 질문 몇가지 드립니다.

 

1. 스택 프레임에서 RDI 레지스터는 무슨 역할을 하는 것인가요? 복사 목적지 주소 레지스터를 의미하는 것 같은데 어떤 값을 push 하는 건지 모르겠습니다.

 

2. 영상에서의 temp와 같은 역할을 하는 메모리가 생기는 조건 같은 것이 있는 건가요? 기본 자료형(Ex. int)을 반환하는 함수를 만들어서 어셈블리로 보니까 호출자 쪽에 따로 접근하는 매개변수는 생기지 않은 것 같아서 의문이 들었습니다. 

 

3. 피호출자 함수가 반환한 값을 호출자 함수에서 따로 저장하지 않고 날린다면 temp가 확보하고 있는 공간은 어떻게 되는건가요? 

 

4. 마지막입니다. 우선 질문에 앞서 코드를 보여드리겠습니다.

#include <iostream>

class Test
{
public:
	Test(void)
	{
		std::cout << this << " : 디폴트 생성자" << std::endl;
	}

	Test(Test&)
	{
		std::cout << this << " : 복사 생성자" << std::endl;
	}

	Test(Test&&)
	{
		std::cout << this << " : r-value 이동 생성자" << std::endl;
	}

	~Test(void)

	{
		std::cout << this << " : 소멸자" << std::endl;
	}
};

Test TestFunc(Test testParam)
{
	Test local;
	return local;
}

int main(void)
{
	std::cout << "****** 시작 ******" << std::endl;

	Test a;
	Test b = TestFunc(a);

	std::cout << "****** 종료 ******" << std::endl;
	return 0;
}

실행결과 입니다.

호출자 함수에서 클래스나 구조체를 선언함과 동시에 피호출자 함수 반환값(클래스or구조체)으로 정의를 하면 어떻게 되는건가 궁금합니다. 이번 강의에서 나온 것처럼 호출자 함수의 temp에 복사된 반환값(임시객체)에 식별자를 부여하고 temp 전체를 지역 변수처럼 활용하는 것인가 생각이 듭니다. 

 

질문이 너무 많은 것 같아 염치 없습니다. 궁금한 부분의 어셈블리어를 직접 확인하면 제일 좋을텐데 아직 어셈블리어가 익숙하지 않아 이렇게 질문 남겨봅니다. 감사합니다.

답변 1

답변을 작성해보세요.

1

1. 스택 프레임에서 RDI 레지스터는 무슨 역할을 하는 것인가요? 복사 목적지 주소 레지스터를 의미하는 것 같은데 어떤 값을 push 하는 건지 모르겠습니다.

함수 내부에서 쓸 레지스터들에 대해 push로 기존 값을 저장했다가 함수가 끝날 무렵 pop해서 복원하는데요. rdi 레지스터는 딱히 중요하지 않아 넘어가셔도 됩니다. (반복문 등에서 사용될 수 있음)

2. 영상에서의 temp와 같은 역할을 하는 메모리가 생기는 조건 같은 것이 있는 건가요? 기본 자료형(Ex. int)을 반환하는 함수를 만들어서 어셈블리로 보니까 호출자 쪽에 따로 접근하는 매개변수는 생기지 않은 것 같아서 의문이 들었습니다. 

기본 자료형의 경우 기본 레지스터 (특히 eax)에 반환 값을 전달하게 만들어지는 경우가 많습니다. 

3. 피호출자 함수가 반환한 값을 호출자 함수에서 따로 저장하지 않고 날린다면 temp가 확보하고 있는 공간은 어떻게 되는건가요? 

함수 호출이 막 시작될 때 esp 레지스터를 쫙 내리는데 이게 해당 함수가 사용하는 스택 공간입니다. [피호출자 함수]가 반환하는 값은 레지스터를 통해 전달되는게 아닌 경우라면, 보통 [호출자 함수]의 스택 프레임 영역에 위치해서 반환되는데요. 그렇기 때문에 그것을 꺼내 쓰지 않는다 해도 딱히 달라질 것은 없습니다. 그리고 애당초 스택 영역은 뭔가를 열심히 [확보하고 날리는] 개념이라고 거창하게 말하기도 뭐한게, 그냥 esp 레지스터를 내리고 올리고 하면서 확보한 영역을 조절할 뿐입니다.

4. 마지막입니다. 우선 질문에 앞서 코드를 보여드리겠습니다.

이건 컴파일러나 환경에 따라 다릅니다.
임시 값을 거쳐 2번 복사되는 경우도 있고,
바로 해당 주소에 값을 쓰는 경우도 있을 수 있습니다.

김기범님의 프로필

김기범

질문자

2021.12.30

답변 감사드립니다. 함수 호출과 반환의 과정을 좀 더 명확하게 알게 된 것 같습니다. 감사합니다.

채널톡 아이콘