LISTORY

[윈도우즈 시스템 프로그래밍]호출 규약과 실행의 이동 본문

IT/윈도우 프로그래밍

[윈도우즈 시스템 프로그래밍]호출 규약과 실행의 이동

LiStoryTeller 2018. 7. 14. 22:51


뇌를 자극하는 윈도우즈 시스템 프로그래밍 책 관련 YouTube 강의 정리이다.


이번 시간에 정리할 내용을 호출 규약과 실행의 이동 부분이다.


YouTube 주소 호출 규약과 실행의 이동



호출 규약과 실행의 이동


이번 장(10장)에선 계속 함수호출이 CPU 내부적으로 어떻게 전개되는지 다루고 있다.


저번 시간과 그 전 시간에 매개 변수 전달, 지역변수 선언 대해 설명하였고, 이번 시간에는 실행의 이동에 대해 설명하겠다.


함수 호출되는 순간, 실행되는 코드가 다른 함수로 이동한다. 이게 어떻게 가능한걸까?


실행의 이동의 키는 바로 프로그램 카운터(PC)이다.





PC는 다음 명령어의 주소값을 가지고 있다.



오른쪽 그림을 보자. 명령어가 코드 영역에 쌓여 있다.


이 명령어들을 실행하기 위해선 하나씩 CPU 내부로 fetch해와야 한다.


PC는 이 명령어를 어디까지 가져왔는지 알려주는 역할을 한다. 


근데 이걸 달리 말해보면, CPU는 PC가 가리키는 위치에 있는 것을 다음번에 실행한다는 뜻이 된다.


예들 들어 보겠다. A, B 함수가 있다. 그 안에 많은 명령어가 있다.


A함수 명령어 실행 중, B함수를 실행하고 싶다.


이럴 경우, PC에 B함수 명령어 위치를 지정하면 된다. 즉, B 함수의 시작값을 PC에 넣는다.


그럼 아무생각없이 CPU 는 PC에 있는 값 가져다가 실행하게 된다.


즉, 실행의 이동이라는 것은 PC의 값을 변경하는 것이다.


즉, PC는 순차적인 실행의 역할을 하기도 하지만 다른 기능은 실행의 이동, 즉 함수 호출도 가능케 한다.



호출된 함수가 실행을 끝내면, 다시 본래의 위치로 돌아가야 한다. 이때 반환은 어떻게 하게될까?


저번 시간에 언급하였던 스택 포인터 & 프레임 포인터 레지스터 관계가 있다. 함수의 호출 및 반환도 이 관계와 같다.


SP & FP 관계에선 SP가 FP에게 백업을 요청하고 FP는 메모리에 백업한다.


PC도 SP와 마찬가지로 값 계속 증가시킨다. 즉, 돌아갈 주소를 어딘가에 저장해야 한다.


PC는 이걸 링크레지스터(LR)에 저장한다. LR도 백업을 메모리, 즉 STACK에 백업시켜 둔다.


다시 정리하자면 다음과 같다.


함수가 호출됐을 때, PC값을 LR에 저장해주어야 한다.


함수호출이 계속 되면 LR에 계속 요청을 하게 되고, 그럼 LR은 메모리에 백업을 한다.




함수호출 규약



어떻게 함수 호출 실행할 것이냐 약속하기 위해 함수호출 규약을 사용한다.


예를들어 A함수 B 함수 존재한다고 해보자. A 함수가 B 함수를 호출했다. 


이 순간 결정해야 할 것이 있는데, B 함수가 끝나고 반환하는 코드를 A 함수에 넣을 것이냐 B 함수에 넣을 것이냐 약속을 해야한다.


즉, 반환하는 코드가 A함수가 컴파일 될때 넣어줄 것이냐 아님 B 함수가 컴파일 될때 거기에 넣어줄 것이냐를 약속해야 한다.


이 부분을 두 함수가 가지고 있음안된다. 둘중 하나만 반환하는 코드를 가지고 있어야 한다.


이걸 누가 가지고 있어야 하는가? 결정하는 것이 바로 함수 호출 규약이다.


이것 뿐만이 아니다.


인자 전달를 전달할 때, A가 왼쪽부터 전달한다했으면 B도 왼쪽부터 채워져야한다. 일치하지 않으면 엉뚱한 데이터가 들어간다.


이것도 함수 호출 규약을 통해 결정한다.


레지스터의 활용 또한 함수 호출 규약을 통해 결정한다.



표를 보자. 


Calling Convention, Parameters in registers, Parameter order on stack, Stack cleaning by 등이 존재한다.


각각에 대해 설명해보도록 하겠다.


1. Stack cleaning by


Stack cleaning by는 함수 호출이 끝났을 때 호출되는 부분으로 누가 clean을 할 지 결정하는 것이다.


caller가 clean? function이 clean? 즉 B함수를 호출한 A함수가 clean할 것인지, 호출된 B 함수가 clean할 것인지 결정한다.


이는 이제 caller가 clean하는 것으로 픽스되었으므로 크게 중요하지 않다.


2. Parameter order on stack


스택에 어떠한 순서로 인자를 쌓을 것인지 결정한다. 여기서 c는 c 스타일을 의미한다.


인자를 오른쪽에서 왼쪽으로 쌓는 것이 c스타일이다.


인자를 왼쪽에서 오른쪽으로 쌓는 것은 파스칼 스타일이라 하는데, 이 부분은 위와 마찬가지로 c스타일로 픽스되었다.


3. Calling Convention & Parameters in registers


32비트에선 네가지 약속, 64비트에서는 윈도우즈, 리눅스로 크게 나뉘어 진다.


함수를 통해 전달되는 매개변수가 32비트 환경에서는 스택에서만 쌓인다.


근데 32비트의 Calling Convention을 보면 _fastcall이라는 것이 존재한다. 


이는 매개변수 두개까지는 Parameter in register에 존재하는 두개의 레지스터에 저장한다는 뜻이다. 


즉, 매개변수 두개까지는 레지스터에 저장하고, 그 이후부터는 스택에 저장하겠다는 것이다.


당연히 스택보다 레지스터가 훨씬 빠르기 때문에 속도가 빨라지므로 _fastcall이라고 한다.


64비트부터는 레지스터 네개까지 가능하므로 32비트보다 훨씬 빨라진다.


리눅스같은 경우에는 훨씬 더 많은 레지스터 사용한다.


Comments