LISTORY
[윈도우즈 시스템 프로그래밍] 절차적 함수 호출 지원 CPU 모델 본문
뇌를 자극한는 윈도우즈 시스템 프로그래밍 책 관련 유트브 강의 내용 정리이다.
오늘 정리할 내용은 절차적 함수 호출 지원 CPU 모델 부분이다.
⊙ YouTube 주소 ⊙ ☞ 절차적 함수 호출 지원 CPU 모델
절차적 함수 호출 지원 CPU 모델
이번 시간에 공부할 내용은 함수 호출에 관련된 이야기다.
함수 호출을 실행할때 CPU가 내부적으로 함수 호출을 어떻게 처리할까?
일단 함수 호출을 하면 떠오르는 것들이 있다.
⊙ 함수호출 하면 떠오르는 것?
1. 인자 전달
2. 지역 변수
3. 실행의 이동(A함수 -> B함수)
이 강의에서는 지역변수가 내부적으로 어떻게 처리되는지 정리할 것이다.
⊙ 스택 프레임(Stack Frame)이란?
메인함수에서 변수 두개 선언 및 함수를 호출하였다.
변수 a,b는 메인에서 선언되었다. 즉, 메인함수의 데이터 블럭이고
이것을 메인 스택 프레임이라 말한다.
변수 c,d는 fct1함수의 데이터 블럭이다. 즉, fct1 스택 프레임이 된다.
임의의 함수 내에서 선언된 메모리 공간을 스택 프레임이라 한다.
근데 여기서 신기한 점이 있다.
모두가 아다시피 컴퓨터는 우리가 시키는 일만 한다.
하지만 여기서 우리가 변수의 위치등을 아무것도 지정해 주지 않았는데, 변수들이 차곡차곡 겹치지 않고 메모리 공간에 저장된다.
이게 어떻게 가능한 것일까?
관찰자가 있다고 가정해 보자. 관찰자는 첫번째 메모리 블럭, 즉 첫번째 주소를 가리킨다.
이 첫번째 메모리 블럭, 즉 a라는 변수에 1이라는 값이 들어갔다. 그럼 관찰자는 자동으로 그 다음 메모리 공간을 가리킨다.
변수 b에 2가 들어갔다. 그럼 관찰자는 그 다음 메모리공간을 가리킨다.
이렇게 위치를 저장하고 어디까지 메모리 공간 할당했는지 기억해주어, 메모리에 차곡차곡 쌓도록 도와주는 것이 스택 포인터 레지스터이다.
⊙ sp 레지스터
SP가 처음에 변수 a를 가리킨다. 그리고 변수가 선언될때마다 그 다음 주소를 스택 포인터에 다시 저장한다.
이렇게 쌓고 기억하는건 어렵지 않다. 문제는 함수를 반환할 때이다.
단순히 쌓기만 했다고 가정해보자.
스택포인터는 쌓은 위치를 기억한다.
그러다가 함수 FCT1을 호출하고, 함수가 끝나 반환되었다. 이때, 스택 포인터는 어디로 가야할지 모른다.
왜냐하면 SP는 레지스터이고, 주소값을 하나밖에 저장하지 못하기 때문이다. 즉, 그 정보를 기억하고 있지 않다.
이 문제를 해결하기 위해 되돌아갈 주소를 기억하기 위해 또 하나의 레지스터 사용한다.
이게 프레임 포인터 레지스터이다.
⊙ fp 레지스터
FP는 간단히 말해 SP의 백업이다.
SP는 뭘 백업해야할까?
함수가 호출됐을 때, 예를 들어 Main에서 FCT1 호출했다고 해보자.
FCT1 끝났을 경우, 다시 MAIN으로 돌아가야한다. (함수 호출되기 이전의 상태)
그럼 함수 호출되기 이전 상태를 기억해야하는데, 이 위치를 FP가 저장하는 것이다.
그림을 보자.
함수 FCT1이 호출되자마자 SP가 자신의 값(main에서의 위치)을 FP에 저장한다.
그 상태에서 SP가 자신의 값을 계속 증가시킨다.
FCT1함수가 끝나고 반환이 되었다.
여기서 잠시 반환에 대해 다루도록 하겠다.
⊙ 함수의 반환
함수가 반환되었다는 것은 어떤 상태를 말하는 걸까?
함수가 반환되면 메모리 공간이 초기화 되거나 반환되는 것이 아니다.
이건 단순히 스택 포인터가 가리키고 있던 위치를 함수 호출 이전으로 되돌린다는 것이다.
즉, 반환된 상태에서 다시 데이터가 들어오면 기존의 데이터가 덮어써진다.
그러므로 SP의 값이 덮어써지는 것을 방지하기 위해, 프레임 포인터에 백업할 필요가 있다.
반환한 다음에는 프레임포인터의 값을 다시 가져오고, SP는 그 값을 가리킨다.
근데 또 문제가 있다.
이제까지 다룬 부분은 함수에서 하나의 다른 함수를 호출할 경우이다.
그렇다면 함수에서 다른 함수를 호출, 그 함수에서 또다른 함수를 호출하는 식으로 연속해서 계속 다른 함수를 호출하면 어떻게 될까?
예를 들어 메인 함수가 FCT1 함수 호출 FCT1 함수가 FCT2 호출했다고 해보자.
함수의 호출이 계속 되면 SP는 이것도 백업 저것도 백업 계속 요구하게 된다.
근데 FP는 하나의 레지스터이다. 아다시피 하나의 레지스터에 많은 정보를 담을 수 없다.
즉, SP가 계속 백업을 요구할 시, FP가 가지고 있는 값이 덮어진다. 당연히 이렇게 되면 동작이 정상적으로 이루어지지 않는다.
그러므로 FP도 백업이 필요한데 재귀함수등 생각해보면 이게 너무 많다.
그래서 결국은 레지스터 말고 메모리를 백업으로 둔다.
다시 위에 그림을 보자.
밑의 FCT2 함수 호출 시(그림 잘못됨), 또다시 백업 필요로 한다. 그래서 메모리를 별도로 두어야한다.
이 메모리 역시 스택이다.
⊙ 해결책
SP가 현재 8번지를 가리키고 있고, FCT1이 호출이 되었다고 가정해보자.
다른 함수가 호출되었으므로, SP는 FP에 자신의 데이터를 백업한다.
그래서 FP 는 8번지를 가지고 있는다.
이 상태에서 다시 FCT2가 호출되었다. 그럼 SP는 또 백업 부탁하게 된다.
여기서 FP에 바로 또 백업을 시행하면 번지8이라는 값이 날라가게 된다.
그러므로 FP가 자신의 값을 현재 SP가 가리키는 위치에 저장하다.
즉, SP에 FP가 가지고 있는 데이터 값이 저장되고, 이 값이 덮여씌워지면 안되므로 SP가 가리키는 위치도 하나 증가한다.
그리고 FP는 SP가 가지고 있는 값을 또 백업, 즉 20번지를 갖게 된다.
이 상태에서 계속 진행이 되어 SP에는 8번지 값 위에 변수 e, h가 저장된다.
이 상태에서 함수가 반환되었다.
반환되면 FP는 자신이 가지고 있는 값을 도로 SP 에 저장한다.
즉, 20번지 값을 SP가 가리키게 한다. 그리고 SP가 현재 가리키고 있는 주소의 값(데이터)을 다시 FP에 저장한다.
그래서 SP는 20번지를 가리키고, 그 안에 있는 위치 데이터 값, 즉 8번지를 다시 FP에 저장한다.
함수가 반환되는 과정을 다시 정리하자면 이와 같다.
함수가 반환되며 FP, 즉 SP의 백업이 가지고 있는 값을 SP가 가리키게 된다.
그리고 SP가 가리키고 있는 위치의 데이터를 다시 FP가 가리키게 되는 것이다.
'IT > 윈도우 프로그래밍' 카테고리의 다른 글
[윈도우즈 시스템 프로그래밍]호출 규약과 실행의 이동 (0) | 2018.07.14 |
---|---|
[윈도우즈 시스템 프로그래밍] 함수 호출 인자의 전달과 PUSH&POP 명령어 디자인 (0) | 2018.07.08 |
[윈도우즈 시스템 프로그래밍] Windows 프로세스 우선순위 (0) | 2018.07.07 |
[윈도우즈 시스템 프로그래밍] 스케줄링 알고리즘과 우선순위 (0) | 2018.07.07 |
[윈도우즈 시스템 프로그래밍] 프로세스간 통신(IPC) (0) | 2018.07.01 |