본문 바로가기

CS

프로시저

프로시저 호출은 소프트웨어에서 중요한 추상화이다.  이들은 지정된 인자들과 리턴 값으로 특정 기능을 구현하는 코드를 감싸주는 방법을 제공한다. 프로시저에 대한 기계어수준 지원을 제공할 때 처리되어야 하는 여러 가지 많은 특성들이 존재한다. 프로시저 P가 프로시저 Q를 호출하고, Q가 실행한 후에 다시 P로 리턴한다고 가정하자. 이러한 동작들은 다음과 같은 하나 이상의 메커니즘이 연관된다

  • 제어권 전달: PC(프로그램 카운터) 는 진입 할 때 Q에 대한 코드의 시작주소로 설정되고, 리턴할 때는 P에서 Q를 호출하는 명령어 다음의 명령어로 설정되어야 한다.
  • 데이터 전달: P는 하나 이상의 매개변수를 Q에 제공할 수 있어야 하며, Q는 다시 P로 하나의 값을 리턴할 수 있어야 함.
  • 메모리 할당과 반납: Q는 시작할 때 지역변수들을 위한 공간을 할당할 수도 있고, 리턴할 때 이 저장소를 반납할 수 있다.

위에서 말한 메커니즘을 이해하기 위해 재귀 프로시저를 예시로 보겠다.

그 전에 프로시저에 대해 기억하면 좋을 것들에 대해 정리해 보겠다. 

  • 프로시저는 최대 6개의 정수 값들을 레지스터로 전송할 수 있지만, 만약 호출되는 프로시저가 더 많은 인자를 요구한다면 이들은 호출하기 전에 자신의 스택 프레임 내에 P에 의해 저장될 수 있다. 그래서 만약 인자가 수자 적다면 굳이 스택프레임을 요청하지 않는다.
  • 제어의 이동에과 관련해서 예제 코드 실행 결과를 보자

여기서 %rsp 즉 스택 포인터와 PC값을 주목하면 좋겠다. 

 

  • 데이터 전송 부분에서 알아둬야 할 것은 인자 6개를 받을때 operand 사이즈에 따라 다르게 받는다

예를 들자면 첫번째 long 타입 인자 같은 경우 rdi로 받고, 그 뒤 int형 인자가 2번째라면 %edx로 받는다.

  • 스택에서의 지역 저장공간이 필요한 이유는 위에서 언급한 것처럼 레지스터 수가 부족하고,  변수의 주소를 생성 할 수 있어야 하거나, 일부 지역변수들이 배열 또는 구조체여서 이들이 배열이나 구조체 참조로 접근되야 한다.
  • 레지스터들은 모든 프로시저들이 공유하는 단일 자원의 역할을 한다. 비록 어떤 한순간에는 오직 하나의 프로시저만이 활성화될 수 있지만, 하나의 호출자프로시저가 다른 피호출자를 호출할 때, 피호출자는 호출자가 나중에 사용할 계획인 일부 레지스터 값은 덮어 쓰지 않는다. 관습적으로 레지스터 %rbx, %rpb, %r12- %r15는 피호출자-저장 레지스터로 구분한다.

이제 재귀 프로시저를 한번 보자

아래는 c코드다

long rfact(long n)
{
	long result;
    if(n<=1)
    	result =1;
    else
    	result =n * rfact(n-1);
    return result

다음은 생성된 어셈블리 코드다

팩토리얼 코드

먼저 스택에 기존 값을 보관한 후에 레지스터 %rbx를 매개변수 n을 저장하기 위해 사용한다. 이건 나중에 재귀적으로 rfact함수가 호출 된 뒤 결과값과 다시 계산하기 위해 사용된다.

'CS' 카테고리의 다른 글

CPU 가상화  (0) 2021.10.04
커널 레벨 쓰레드와 유저 레벨 쓰레드  (0) 2021.10.02
전통적 동기화 문제와 데드락  (0) 2021.09.26
동시성 이슈  (0) 2021.09.25
Nonlocal jumps  (0) 2021.09.24