minhui study

3부 10장 - 1. 함수 호출 관점에서의 컴퓨터 구조 이해 본문

컴퓨터 구조/Windows System Programming

3부 10장 - 1. 함수 호출 관점에서의 컴퓨터 구조 이해

minhui 2020. 1. 23. 20:40

[목차]

1. 절차적 함수 호출 지원 CPU 모델

2. 함수 호출 인자의 전달과 PUSH & POP 명령어 디자인

3. 함수 호출에 의한 실행의 이동

4. 함수 호출 규약

 


Section 01. 절차적 함수 호출(Procedure Call) 지원 CPU 모델

 

> Stack Frame 구조

 

다음 그림은 함수 호출과 스택 관계를 보여준다. 

 

-> Stack Frame 

: 함수 호출 과정에서 할당되는 메모리 블록

 

fct2 함수가 호출되면서 이 함수 내에 선언된 변수 e와 h가 스택에 할당되는데 미 메모리 블록을 가리켜 스택 프레임이라 한다. fct2 함수가 반환되면 이 스택 프레임은 모두 반환된다. 스택 프레임은 가장 먼저 할당되면 가장 나중에 반환된다.

 

 

 

 

 

 

 

 

> sp(Stack Pointer) 레지스터

 

계속해서 스택에 데이터를 쌓거나 반환하기 위해서는 현재 어느 위치까지 데이터를 저장했는지(쌓아 올린 스택의 위치) 기억해야 한다. 이를 위해 CPU 내에 sp(Stack Pointer)라는 이름의 레지스터가 존재한다.

 

[10-2] sp 레지스터의 역할

sp 레지스터값은 변수가 하나 하나씩 할당될 때마다 증가하면서 다음 변수가 할당될 메모리 위치를 가리키게 된다. 반면에 호출된 함수가 종료될 경우 그 안에서 선언된 변수들을 동시에 모두 반환해야 하기 때문에 스택 프레임 단위로 sp 레지스터값을 이동시켜야 한다. 변수 선언 시 현재 sp가 가리키는 위치에 할당하기 때문에 sp위치를 아래로 이동시키는 것만으로도 이전에 선언된 변수를 반환할 수 있다. 때문에 sp가 가리키는 위치를 아래로 이동시키는 방식으로 스택 프레임을 반환한다. 

 

> fp(Frame Pointer) 레지스터

 

할당하고자 하는 변수가 4바이트 정수형이라고 하면 sp값을 4만큼만 증가시키면 되지만 메모리 공간을 반환하기 위해 sp를 아래로 아동시킬 때는 CPU에서 함수가 빠져나오는 시점에서 얼마만큼 sp를 이동시켜야 할지 알 수 없기 때문에 문제가 되는데 이 때 필요한 것이 프레임 포인터 레지스터이다.

 

[10-3] fp 레지스터의 역할

위 그림에서 fct1 함수를 호출하는 과정을 보면 sp 레지스터에 저장된 값은 fp레지스터에 저장한다. 그렇게 되면 아무리 많은 변수를 선언한다 하더라도 함수 fct1 반환 이후 그림처럼 fp레지스터에 저장된 값을 참조해서 fct1 함수 호출 이전 위치로 sp를 이동시킬 수 있게 된다. 즉, fct1 함수의 스택 프레임만 날아가 버린 것이다.

하지만 fp로 모든 문제가 해결되는 것은 아니다. [10-2]그림처럼 함수 호출로 함수 호출이 중첩된다면 문제가 발생한다.

 

[10-4] fp 레지스터의 문제점

위 그림을 보면 fct1 함수가 호출되면서 sp레지스터 값을 fp레지스터에 저장하고 있는데 그 뒤에 fct1함수가 fct2함수를 호출한다. 변수 c와 d를 선언하느라 증가된 sp값을 다시 한번 fp에 저장하게 되는데 그렇게 되면 fct2함수의 스택 프레임 반환을 위한 주소 정보가 fct1함수의 스택 프레임 반환을 위해 저장한 주소 정보를 덮어 써버리고 만다. 결국 fct1함수를 반환할 때 fp 레지스터값을 참조할 수 없게 되어 sp레지스터가 가리켜야 할 위치를 찾지 못하게 된다.

 

> 스택에 저장하자, Frame Pointer

 

덮어쓰는 문제가 해결하기 위해서는 함수 호출이 일어날 때마다 fp레지스터에 저장되어 있는 값을 스택에 저장하면 된다. 

[10-5] fp 레지스터와 스택

[ 1단계 ] 

fct2 함수가 호출되기 직전에 sp레지스터에는 주소값 20이 들어가 있다.(현재 스택 주소)

 

[2단계]

fct2 함수가 호출되기 직전에 fp레지스터에는 주소값 8이 들어가 있다.(8 -> main함수와 fct1함수의 경계)

 

[3단계]

fct2 함수가 호출되면서 fp레지스터 값(8)을 현재 sp레지스터가 가리키는 위치 20번지에 먼저 저장한다.

그 다음 fp에 sp값 20을 저장한다. (20 -> fct1 스택과 fct2 스택의 경계) 

 

[4단계]

fct2 함수를 반환하고자 한다면 fp레지스터에 저장된 값을 참조해서 sp레지스터값을 20으로 변경한다.

 

[5단계]

현재 sp가 가리키는 위치에 저장되어 있는 값을 fp에 옮겨다 놓는다. 이로써 fct1 함수가 반환되는 상황에서 sp의 위치를 8번지에 가져다 놓을 수 있다.(8 -> main함수와 fct1함수의 경계)

 

 

 

출처 : 윈도우즈프로그래밍 (한빛미디어)

 

 

Comments