본문 바로가기

무언가 만들기 위한 지식/SPARC Assembler

Assembler Recursive Subroutine(Function)

요구사항
Subroutine을 이용하여 피보나치 수열을 구현하라.
입력을 받으면 해당 f(n)을 n, f(n)형식으로 출력하라.
입력도중 0미만, 즉 음수를 입력받을 경우, n을 다시 입력 받도록 한다.
정상적인 출력후에도 반복하여 n을 입력받아 계속 연산을 수행한다.
단 사용자로부터 Ctrl+D를 입력받을 경우에는 프로그램을 종료한다.

구현내용
재귀적 프로그램하면 항상 나오는 Fibonacci를 구현하는 과제이다.
피보나치 수의 정의는 f(0)=0, f(1)=0, f(n)=f(n-1)+f(n-2) 이다.
재귀적으로 구하게되면 꽤나 직관적으로 간단하게 짤 수 있는 프로그램이다.
Subroutine을 공부하면서 스택에 쌓여가는 과정을 생각해 볼 수 있었다.

※ 사실 재귀함수는 작성하기에 편하지만, iterative적인 프로그램보다 비효율적이다. 실제로 스택에 쌓여가면
    계산하여야 하는 횟수가 더 많다. 내부적으로는 이미 한 연산을 다시 하는 과정을 겪게 된다.

프로그램상에서 별다른 명령어를 사용하지는 않았다.
다만 Subroutine의 위치 및 함수를 사용하는 방법에 관한 것이 문제였다.
함수를 선언할때는 main을 global로 선언하기 전과 static영역(section data~text) 설정사이에 선언한다.
또한 global로 선언하여 사용한다.
subroutine이란 스택에 쌓여져 올려지면서 수행되는 하나의 단위이다. C언어의 함수와 같다.
Assembler의 불편한점은 한번에 5개의 레지스터를 이용하여 인자를 전달할 수 있다는 것이다.
인자 전달과 리턴값을 호출된함수(callee)와 피호출자(caller) 사이에서는 Register %i0~%i5,%o0~%o5사이에서 주고 받는다.
자세한 설명은 후에 하도록 하고 실전에서 알아둬야 할 것은
Main에서 함수로 인자를 전해줄때는 %o0~%o5를 이용하는 것이고, 받을때는 호출후 %o0~%o5를 이용한다.
그리고 호출된 함수 입장에서는 받은 인자는 %i0~%i5에 맵핑되고, 리턴 할 값은 %i0~%i5에 넣어 주면 된다.

가장 생각하기 쉬운예가... 우리가 처음 사용해본 함수 .mul의 경우 %o0와 %o1에 인자를 전달해주고 %o0에 값을 받은 것을 생각하면 된다. 호출된 함수에서는 %i0, %i1로 받아 그 스택에서 사용하고 %i0로 리턴해 준것이다.
i레지스터와 o레지스터는 표현상은 다르지만 실제공간에서는 같이 값을 나타낸다는 사실을 명심하기 바란다.
(정확히는 caller의 o레지스터와 callee의 i레지스터가 같은 것임)


[작성환경 : solaris sparc machine  작성툴 : Vi editor   컴파일러 : gcc]


<실행결과 : 0 또는 양수를 입력받으면 결과를 출력, 음수일때는 다시 입력받고 ctrl+d를 입력받자 종료한다.>
코드분석
만든 함수인 fib를 보면 그 안에서 save를 이용하여 메모리를 할당하고 마지막엔 ret와 restore가 있는 사실을 알 수 있다.
즉 메인처럼 하나의 스택이다. 메인또한 이런 서브루틴의 일종이기 때문에  save도 있고 리턴이 있는 것이다.

참고로 ret는 jmpl명령어의 조합이다.(즉 리턴해야할 곳의 주소를 저장하고 그곳으로 간다는 의미)
restore는 메모리는 비워주는 명령어이다. 내부적으로 add연산기능도 가지고 있다.
코드에서는
ret
restore
라고 적혀있는데, 이것은
restore
ret
nop

과 같은 의미이다. ret자체가 파이프라인의 특성으로 nop을 써주어야하는데 줄여 쓴 것이다.

위에서 인자를 전달할때 6개의 레지스터로 전달이 가능하고 하였는데,
실제로 더 많은 값의 전달도 가능하다. 이는 호출된 함수에서 피호출된 영역의 공간을 끌어다 쓰는 원리를 이용한다.

요구사항을 보면 Ctrl+d를 입력받으면 종료인 부분이 있다.
이부분은 외부 시그널을 받아오는 것인데.
scanf로 받을 준비가 되어 있는데 ctrl+d시그널을 받으면 scanf호출후 %o0에 -1값이 들어오게 된다.
즉 scanf후 %o0값을 확인하여 -1일 경우 종료하고 아닐경우 다시 입력받는 순서고 구성되어 있다.
(scanf는 원래 설정한 공간에 값이 저장됨. %o0등에 저장되는 것이 아님.)