한줄 요약 : 스택에 저장하는 값 -> 복귀주소, 로컬변수, 파라미터

 

  • 복귀주소 (Return Address) :  프로시저가 해당 기능을 끝마친 뒤 다음 코드의 내용이 실행될 수 있게 아래와 같은 이유로 복귀주소를 스택에 저장. 
    • 프로시저가 호출 되기 직전에 저장했다가, 끝나게되면 복귀주소 역시 필요 없어 진다.
    • 프로시저 안에서 또다른 프로시저의 호출이나 , 재귀 등의 흐름이 가능하므로, 복귀주소가 중첩하여 여러개 존재할 수 있다 -> 즉, 복귀주소들 간의 순서를 나타낼 수 있어야한다.

 

  • ESP(Extended Stack Pointer) : 현재 스택의 위치(스택에서 가장 아랫부분)를 저장
  • EBP(Extended Base Pointer) : 스택의 처음값을 저장 -> 스택프레임이 소멸되지 않는 한 유효하다.
  • EIP(Extended Instruction Pointer) : 다음번에 해야할 일 저장 (실행위치)
  • 함수가 종료되고 난 후, 쓰레기가 된 로컬변수나 복귀주소 값 등은 다음 프로세서가 덮어쓰기로 사용함으로써 별도의 메모리할당 또는 해제 작업 없이 메모리영역을 재사용한다.

그렇다면 파라미터 저장은 어떻게 해야할까? 

아래와 같은 코드를 보자 

main()
{
	sum(1,2);
}

int sum( int a, int b)
{
	return a+b;
}

이 코드가 실제 스택에 저장되는 형태는 다음과 같다.

32bit환경 기준,

현재의 ESP의 4Byte 데이터 = 복귀 주소

ESP+0x4의 4Byte 데이터 = 첫 번째 파라미터

ESP+0x8의 4Byte 데이터 = 두 번째 파라미터 

 

하지만 위 처럼 계산할 시에 문제점이 발생할 수 있다.

바로 sum함수 내에서 스택의 내용을 변경하는 코드가 있다면, ESP기준으로 파라미터를 가져올 때 잘못된 값을 가져올 수 있기 때문이다.

이와 같은 문제를 해결하기 위해 컴파일러가 알아서 계산을 해주기도 하지만, 또다른 방법으로는 스택 프레임을 구성하여 해결하고 있다.

 

  • 스택 프레임(Stack Frame) : 호출된 프로시저의 복귀 주소를 기준으로 고정된 변위값을 통하여 파라미터를 다루는 것

따라서 파라미터 값을 가져올때는 Push나 Pop등에 영향을 받지 않는 EBP레지스터를 기준으로 삼는다.

 

아래와 같은 코드는 메모리 참조 오류를 발생시킬 것이며, 스택 백트레이싱을 통해 버그의 원인을 찾을수 있다.

main()
{
	char buf[4];
	strcpy(buf, "Test");

	func1(buf);
	func1(0);
}

void func1( char* buf )
{
	int a, b;
	.
	.
	.
	func2(buf);
}

void func2( char* buf )
{	
	int c ;
	.
	.
	*buf = 'A'
}

이는 다음과 같이 저장된다.

  • 참고사항 : 함수의 리턴값은 스택에 저장하는 것이 아니다. 32비트의 경우 EAX레지스터에, 64비트의 경우 낮은 주소영역의 32비트 내용은 EAX에, 높은 주소영역의 경우 EDX에 저장한다.
    특정 프로시저의 리턴값을 알고자 할 때에는 그 함수가 리턴된 후의 EAX값을 참조하면 된다.

Windows에서 스레드 생성시 디폴트로 1MByte의 메모리를 예약(이 사이즈는 컴파일러 옵션으로 조정할 수 있다.)하는데 이 중 1개의 페이지인 4KByte만을 실제 메모리와 매핑시키고 나머지는 가드페이지 라는 예약된 형태로 만들어 놓게 된다.

Q. 그럼 예약된 가드페이지를 온전히 스택의 값을 저장하는데 쓸까?

A. 정답은 아니다. 맨 아래 페이지는 이전과 같은 예약상태로 놓아둔다.

이러한 이유는 스레드 전체 영역에 대해 모두 사용하게끔 한다면, 해당 스택을 사용하는 스레드가 자신의 스택범위를 넘어 사용한다 할 지라도 이를 알아차리지 못할 것이다. 

만약, 그 아랫부분에 다른 데이터 영역이 존재한다면 이 데이터 영역을 손상시키며 스택오버플로 에러는 발생하지 않을 것이다 ㅜㅜ 

따라서 항상 예약되어 있는 페이지를 만들어 둠으로써 경계를 지킨다.

'Programming > Windows' 카테고리의 다른 글

[WINDOWS] 프로세스  (0) 2021.06.09
[WINDOWS] 윈도우 기본 개념 (2)  (0) 2021.06.09
[WINDOWS] 윈도우 기본 개념 (1)  (0) 2021.06.09
[windbg] Windbg 사용법 / 덤프 분석  (0) 2021.02.23
[windows] 프로세스와 스레드  (0) 2021.02.13
복사했습니다!