# 함수호출 인자의 전달과 PUSH & POP 명령어 디자인
어셈블리 언어라고 해서, 레지스터들을 일일이 직접 컨트롤 해야만 하는 것은 아니다. 잘 정의된 명령어를 제공하므로써,
레지스터를 직접 컨트롤하는 수고를 덜어주는 경우도 있다.
우리는 추가적인 명령어 2가지를 더 정의하고자 한다. (스택에 관련된 연산을 보다 용이하게 하기 위하여)
참고> 함수 호출 / 프로시저 호출 의 구분
1) 함수호출 - 입력에 대한 출력이 반환값으로 존재하는 경우
2) 프로시저 호출 - 출력에 해당하는 반환값 없이 모듈화해 놓은 서브 루틴(Sub-Routine)의 실행을 위한 호출
우리가 초점을 맞출 질문들
--------------------------------------------------------------
" 함수 호출 시 실행위치의 이동은 어떻게 이뤄지는가? "
" 함수 호출 시 전달되는 인자들은 어떻게 함수 내부로 전달되는가? "
" 함수 호출이 끝나고 나면 어떻게 이전 실행위치로 복귀하는가? "
--------------------------------------------------------------
# 함수호출 인자의 전달방식
함수 호출 시 전달되는 인자를 어디에 둘 것이냐에 대한 해답 -> CPU, 혹은 CPU제조사의 표준마다 다르다.
반드시 모든 전달인자들이 스택에 할당되는 것은 아님 !!
-> 성능 향상을 위해서 일부 전달인자들은 레지스터를 할당해서 이곳에 저장하도록 제품의 표준을 정의함
참고> 실제로 ARM코어와 64비트 인텔코어는 레지스터를 적극활용 함
-> "하지만, 우리의 레지스터는 8개 밖에 없으므로, 함수 호출 시 전달되는 인자들은 모두 스택에 저장할 것이다."
# PUSH & POP 명령어 디자인
인자 전달의 핵심연산 = 지역변수의 할당과 동일
"sp가 가리키는 현재 위치에 전달되는 인자값을 저장 후, sp증가시켜 다음 메모리주소를 가르키게 함"
-> 그럼, 이제 인자전달 연산을 위한 명령어를 구성해보자.
(이왕이면 sp값의 증가까지 구현범위에 포함시키자 = 전달인자 스택에 쌓이면 sp값이 증가되어야 함)
STORE 대상(레지스터), 목적지(메모리주소)
1) 첫번째 피연산자 정보는 레지스터가 와야한다.
ADD r1, 7, 0 : 우리는 MOV같은 명령어를 만들어 놓지 않았으므로, ADD를 대용으로 사용한다. (MIPS코어 어셈블리 프로그램 스타일)
2) 두번재 피연산자 정보는 주소정보가 와야한다.
STORE sp, 0x40 : Indirect모드 연산을 위해서 sp가 가진 값을 0x40번지(다른 메모리 주소여도 상관없다)에 저장한다.
STORE r1, [0x40] : 0x40번지를 참조해(그 안에 저장된 sp가 가르키던 주소값이용)서 r1 레지스터의 정보를 메모리에 저장한다.
위에서 sp레지스터의 값이 0x80이었다면 0x80에 7을 저장하게 된다.
ADD r1, 7, 0
STORE sp, 0x40
STORE r1, [0x40]
-> 간단히 설명하면, 숫자7을 sp가 참조하는 메모리 영역에 저장한 것이다.
3) 자, 이제 스택에 데이터가 저장되었으니, sp 레지스터의 값을 증가시키자.
ADD sp, sp , 4 // 저장된 값이 4바이트 이므로, 4바이트만큼 위로 증가시킨다.= 스택은 올라갈수록 메모리값 증가함
[ 완성 ]
--------------------
ADD r1, 7, 0
STORE sp, 0x40
STORE r1, [0x40]
ADD sp, sp , 4
--------------------
하지만, 매번 함수 호출이 빈번한 프로그램에서 이런 명령어들을 일일히 조합하는 것이 프로그래머를 상당히 괴롭히는 일이므로,
스택연산에 도움이 되는 두개의 명령어를 추가해보자
1) PUSH : 현재 sp값을 참조해서 해당위치레 데이터를 저장하고, sp값 또한 자동으로 증가시키자
예) "PUSH 0x02" or "PUSH r1"
2) POP : 4바이트 POP연산으로 제한해 버리자.(스택에 저장되는 모든 데이터를 4바이트로 가정)
예) POP = "ADD sp, sp, -4"와 동일한 의미
이제 총 8개의 명령어가 구성되었다.
지금까지 내용을 정리하는 차원에서, 아래 제공하는 c코드를 어셈블리 코드로 바꿔보고, 실행시 예상되는 스택구조도 함께 그려보자.
7 8
void fuc(int a, int b)
---------------
0x80 번지 <----------------- sp 레지스터 (0x80)
---------------
---------------
0x20 0x40 번지 <----------------- fp 레지스터 (0x40) // fp가 0x40번지를 가르킨다는 것은 어디까지나 가정임.
---------------
stack
---------------
0x8c 번지 <----------------- sp 레지스터 (0x8c) - (PUSH 8후 위치)
---------------
8 <------------------ sp (PUSH 7후 위치)
---------------
7 <------------------ sp (PUSH fp후 위치)
---------------
0x40 0x80 번지 <----------------- fp 레지스터 (0x80)
---------------
---------------
0x20 0x40 번지
---------------
stack
------------------------------------------------
PUSH fp
ADD fp, sp, -4 // 앞에서 디자인한 PUSH명령어를 잘 보자.
// PUSH하면 이미 sp값이 4만큼 증가된다. 만약 sp값에서 4만큼 빼지 않으면, fp는 숫자 7이 저장된 위치를 가르킴
PUSH 7
PUSH 8
------------------------------------------------
// fp 레지스터에 저장된 값을 스택에 옮겨놓았으면, sp의 값을 fp에 저장할 차례다. -4를 뺀이유는 위에 있다.
자, 나머지는 다음에 하자. 피곤하당~ 12시 집에 가자. ^_^
'IT개발 > 컴퓨터구조' 카테고리의 다른 글
컴퓨터 구조에 대한 설명(3-1) 절차적 함수 호출(Procedure Call)지원 CPU모델 (0) | 2010.11.14 |
---|---|
컴퓨터 구조에 대한 설명(2-3) / Direct모드 와 InDirect모드 (0) | 2010.11.14 |
컴퓨터 구조에 대한 설명(2-2) / LOAD & STORE 명령어 디자인 (0) | 2010.11.14 |
컴퓨터 구조에 대한 설명(2-1) (0) | 2010.11.14 |
컴퓨터 구조관련 정리(1) (0) | 2010.11.14 |