컴퓨터 구조론

[컴퓨터 구조론]4. Calling Convention

myjeongjun 2025. 1. 2. 19:32

Calling Convention

DataPath부분으로 넘어 가기전 이 책에서 소개하는 calling Convention에 대해 소개해 보자 한다.

함수 호출도중에 함수에서 사용해야할 레지스터는 그 함수 외에는 건드려선 안될것이다.

그렇지만 레지스터의 수는 정해져있고, 그렇기 때문에 함수내에서 또 다른 함수를 call했을때 호출자(call)와 호출당한 비호출차(callee)들이 서로 같은 레지스터를 사용하게 되어있으면 어느 한값이 덮어씌어져버린다.그 결과 callee의 작업이 끝나고 반환되었을때, 데이터가 손상되어있을수있다.

 

그렇기 때문에 망가뜨려선 안될 register들을 저장하는 Convention을 지정해두었고

그 작업을 caller 혹은 callee가 했을때 구분되는데, 어떤 차이점이 있는지 알아보자.

우선 Caller Save 방식이다. 말그대로 Caller가 Save를 담당한다.

1.live register를 Save한다. 여기서 live란 미래에 사용될 레지스터면 live라는 이름이 붙는다. 즉, 나중에 사용할거기 때문에 저장해둬야 한다는것이다.

2.callee로 넘길 argument를 설정

3.return address를 save하고 callee로 이동하게 된다. return address를 save한 이유는 다른 caller가 나를 call했거나 callee도 또다른 함수의 caller가 될 수있으므로 정확환 반환 위치를 저장해 둬야한다.

 

그리고 위에서 말한 저장되어야할 데이터는 모두 stack에 저장된다.

 

4.callee의 stack frame을 할당한다.

 

5.실행 절차가 끝나면 return 주소를 가져오고 stack frame을 free시킨다(이것이 지역변수는 함수가 종료되면 사라지는지는 이유이다.) 

6.돌아가서 값을 복구한다.

 

 

Callee Save

이건 calle가 register를 save하는 방식인데 caller와는 다르게, update될 수있는 register만 save하는 방식이다.

 

그렇지만 return address는 저장하지않은채로 callee로 jump해버리면 돌아갈 곳을 알 수없게 되버리니 caller가 save해야한다.

이에 더해서 callee입장에서 알 수 없는 레지스터가 3종류있다.

1.V0,V1(return value)

2.return address

3.a0~a3(argument)

 

우리가 공부하고있는 MIPS의 Calling Convention은 Hybrid 방식으로, 아래와 같은 절차를 가진다.

자세히보면 caller가 t0~t9을 save하고 callee가 s0~s7을 save하고있다. $v,$a,$ra는 callee입장에선 알 수없으니 Caller가 저장하는건 그렇다 치고, 왜 일관성있게 한 곳에서 Save하지 않은것일까?

 

그 이유를 살펴보면 위에서 caller는 live한 값만 save를하고 calle는 update하는 값만 save를 하는 방식이었다.

t0~t9은 임시 레지스터로, 보통은 잠깐 사용하는 레지스터이므로 live하지 않을 가능성이 매우높다.

 

그리고 s0~s7는 permanent, 변수들이 들어가므로 live할 확률이 매우 높다. 그러므로 caller와 callee가 live할 가능성을 기준으로 나눠서 save를 하는것이 optimization을 극대화 할수있다고 한다.

 

최종적으로 우리는 이러한 내부적인 설계가 어째서 필요한지 알았고 이제 프로그램을 실행할때 컴파일러에의해 이러한 절차를 따르게된다.

강의에서 소개한 내용은 Linker의 역할이 무엇인가? 이다. Linker는 오브젝트 파일을 하나로 만들어 Executable File을 만드는 역할을 하는데, Linker가 무슨 작업을 하길래 이러한 절차가 꼭필요한것일까 라는 질문을 던졌다.

강의에서 든 예시로는 2개의 오브젝트파일의 함수에 static 변수가 존재했을때의 경우이다,

잠시 개념 설명을 하자면

static

 

automatic(semi-dynamic이라고도한다.)

 

dynamic

이 3개는 메모리 할당과 관련된 개념들이다.

static : 프로그램 시작시 allocated 되며 끝날때 free된다.

 

automatic(semi - dynamic) : 예시로 stack에 allocated(function calll같은 경우, 끝날때 free된다.)동적인성격과 정적인 성격이 섞여있다.

 

dynamic : 동적 할당,C언어의 malloc이라고 생각하면 된다.

 

여기서 automatic을 semi - dynamic이라고도 하는 이유는, stack의 할당 방식은 동적인 성격이 강하긴한데, Stack의 경우 LIFO라는 일관된 패턴에 의해 할당되고 해제 되기 때문에 정확히 동적이라고도 볼 수없다. 이러한 성격을 가진 것들을 모아서 semi가 붙었다고 한다.

 

다시 본론으로 돌아와,

static의 경우  오브젝트 파일을  하나로 합쳐진다면 static data영역에 모이게 되는데, static성격을 가진 변수들을 합쳤을때 어디에 지정해줄지 일정한 규칙이 없기때문에 오브젝트 파일에는 0으로 기입해두고 Linker가 작업할때 어디에 위치할지를 할당해주는 역할을 한다.