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