본문 바로가기

IT개발/컴퓨터구조

컴퓨터 구조에 대한 설명(3-2) / 함수호출 인자의 전달과 PUSH & POP 명령어 디자인

# 함수호출 인자의 전달과 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시 집에 가자. ^_^