Supporting Procedures in Computer Hardware

정태규·2022년 10월 20일
1

컴퓨터구조

목록 보기
4/9

procedure

  • 프로시저나 함수는 이해하기 쉽고 재사용이 가능하도록 프로그램을 구조화하는 방법 중 하나이다.
  • 프로시저는 제공되는 인수에 따라서 특정 작업을 수행하는 서브루틴
  • 함수단위라고 생각하면 편할듯.

MIPS Register convention

  • preserve on call 은 함수를 호출하고 되돌아왔을때 reigster값을 유지해야 하는가 를 물어보는것이다.

  • a0 - a3:전달할 인수를 가지고 있는 인수 레지스터 4개

  • v0 - v1:반환되는 값을 갖게 되는 값 레지스터 2개

  • ra: 호출한 곳으로 되돌아가기 위해 복귀 주소를 가지고 잇는 레지스터 1개

프로그램이 프로시저를 실행하는 단계

  1. main routine(caller)가 프로시저(callee)가 접근할수 있는 곳에 인수를 넣는다.
  2. caller가 프로시저로 제어를 넘긴다.
  3. 프로시저가 필요로 하는 메모리 자원을 획득한다.
  4. 필요한 작업을 수행한다.
  5. 호출한 프로그램이 접근할 수 있는 장소에 결과 값을 넣는다.(v0,v1)
  6. 프로시저는 프로그램 내의 여러 곳에서 호출될 수있으므로 원래 위치에제어를 돌려준다.($ra)

procedure call instructions

호출 프로그램(caller)은 a0-a3에 전달할 인수 값 넣는다. ->
jal x(procedure label) 명령을 이용해서 프로시저x(callee)로 점프한다.->
피호출 프로그램은 계산을 끝낸후 계산 결과를 v0-v1으로 넣는다->
jr $ra 명령을 실행하여 복귀한다.

Leaf Procedure Example

C code:

int leaf_example(int g,h,i,j)
{
	int f;
    f = (g + h) - (i + j)
    return f
}
  • Arguments g,h,i,j는 각각 레지스터 a0,a1,a2,a3에 저장
  • f는 s0에 저장 (s0는 스택에 저장)
  • 결과는 v0에 저장

Compliled MIPS code

leaf_example:
			//백업
            addi $sp, $sp, -12 //sp(stack pointer)의 값을 -12 해주어서 12만큼의 공간($t1,$t0,$s0)을 확보해준다.
			sw   $t1, 8($sp)// sp로부터 8 떨어진 스택 메모리에 t1 저장
            sw 	 $t0, 4($sp)// sp로부터 4떨어진 ...//
            sw	 $s0, 0($sp)// sp자리에 메모리값 s0 저장
            //procedure body
            add $t0,$a0,$a1 //t0 = g+h
            add $t1,$a2,$a3 //t1 = i+j
            sub $s0,$t0,$t1 //s0 = (g+h)-(i+j)
            add $v0,$s0,$zero // $v0에 $s0값 복사
            lw  $s0, 0($sp) //원래 있던 값들을 다시 스택메모리로부터 불러온다 
            lw  $t0, 4($sp)
            lw  $t1, 8($sp)
            addi $sp, $sp, -12 //stack 삭제 시켜준다.
            jr $ra         //return

Non-leaf Procedures

  • 다른 procedure를 호출하는 procedure
int fact(int n)
{
	if(n < 1) return 1;
    else return n*fact(n-1);
}

인수 n은 $a0에 저장
compiled MIPS code:

fact:
	  addi $sp, $sp, -8    // 8byte 스택 메모리 확보
	  sw   $ra, 4($sp) 	   //스택 메모리에 ra를 저장
      sw   $a0, 0($sp) 	   //스택 메모리에 a0 저장
      slti $t0, $a0, 1     // n < 1
      beq  $t0, $zero, L1  // t0가 0이면 L1으로 가라
      addi $v0, $zero, 1   //return값이 1이다.
      addi $sp, $sp, 8     //2스택메모리 pop
      jr   $ra			   //return
L1:
	  addi $a0, $a0, -1	   //인수를 n-1 만든다.
      jal  fact			   //재귀함수, fact로 올라감
      lw   $a0, 0($sp)	   //원래 값 복구시킨다.
      lw   $ra, 4($sp)	   
      addi $sp, $sp, 8	   //확보했던 스택메모리 8 삭제
      mul  $v0, $a0, $v0   //n * result
      jr   $ra			   //return

procedure frame

  • 프로시저의 저장된 레지스터와 지역 변수를 가지고 있는 스택 영역을 프로시저 프레임(procedure frame) 또는 엑티베이션 레코드(activation record)라고 부른다.
  • fp(frame pointer): procedure frame의 첫워드를 가르키는 포인터
    sp가 변할 수 있기 때문에 사용.
  • 인수를 저장하는 register는 a0 - a3 있다. 그렇다면 인수가 4개보다 많으면 어떻게 할까?
    • 나머지 인수는 frame pointer 위 스택에 쌓는다. frame pointer를 통해 언제든 접근가능

memory


text: program code
static data: global variables, 상수나 기타 정적 변수, 배열은 크기가 고정 되어 있기 때문에 static data이다.
heap: malloc(C lang),new(java)
stack: automaitc storage

32 bit constants

  • 대부분의 constants 나 immediate는 16비트로 충분하지만 16비트가 넘어가는 경우 다음과 같이 한다.

  • lui 가 상위 16비트를 읽고 ori가 하위 16비트를 읽는다.
  • 예를들어 $s0에 32 비트 상수를 채우는 어셈블리 코드를 작성한다고하면
    32비트 상수
    0000 0000 0011 1101 0000 1001 0000 0000
    먼저 lui를 통해서 상위 16 비트를 읽는다.
    lui $s0, 61 // 상위 16비트 값이 61임.
    ori $s0, 2304 // 하위 16비트 값은 2304임.
    이렇게하면 $s0에 원하는 값이 들어간다.

branch addressing

  • bne,beq
  • 16bit로 대부분의 constant나 address 표현 가능이유
  • 상대주소를 쓰기 때문
  • target address로 부터 PC가 얼마만큼 떨어져있는지 word 단위로 나타낸다.
  • bne를 보면 address에 2가 써있다.
    target addres인 Exit이 2word 떨어져 있다는 것이다.
    3칸인데 왜 2칸이냐하면, 프로그램 카운터가 해당 instruction이 끝나면 미리 1word 앞으로 미리 전진하기 때문이다.
  • problem
beq $s0, $s1, L1

이 코드를 L1이 아주 멀어도 분기가 가능하도록 바꾸되 명령어 두개를 사용해라

bne $s0, $s1, L2
j    L1
L2:

Jump Addressing

  • 점프할 타겟의 주소 = address ×\times 4

The C code Translation Hierarchy

Assembler

Assembler Pseudo Instructions

move $t0,$t1    -> add $t0,$t1,$zero
blt  $t0,$t1, L -> slt $at, $t0, $t1
				   bne $at, $zero, L

symbol table

  • 어셈블러는 분기나 데이터 전송 명령에 사용된 모든 레이블을 symbol table에 저장한다. 이 테이블은 symbol과 주소를 저장한다.

unix system 목적 파일

  • header: 파일을 구성하는 각 부분의 크기와 위치를 서술한다.

  • text segment: 기계어 코드가 들어 있다.

  • static data segment: 프로그램이 종료 되기 전까지 할당 되어있는 정적 데이터와 프로그램의 요구에 따라 커졌다 작아졌다 하는 동적 데이터 두가지를 프로그램이 사용할 수 있게 한다.

  • relocation info: 프로그램이 메모리에 적재될 때 절대 주소에 의존하는 명령어와 데이터 워드를 표시한다.

  • debug info: 각 모듈이 어떻게 번역되었는지에 대한 간단한 설명이 들어 있다.

Linking object modules

  • Linker

    - 코드와 데이터 모듈을 메모리에 심벌 형태로 올려 놓는다.
    - 데이터와 명령어 레이블의 주소를 결정한다.
    - 외부 및 내부 참조를 해결한다.

  • Linker는 어셈블리로 만든 오브젝트 파일들을 하나의 실행파일로 묶어주는 역할을 한다.

  • 만약에 링커가 없다면 프로시저를 한줄이라도 틀리면 전체 프로그램을 다시 컴파일하고 어셈블해야 한다.

Loading a Program

  • Loader
    - 진행순서

    1. 헤더를 읽어서 텍스트와 데이터 세그먼트 사이즈를 알아낸다.
    2. 텍스트와 데이터가 들어갈만한 주소 공간을 확보한다.
    3. 실행 파일의 명령어와 데이터를 메모리에 복사한다.
    4. 주 프로그램에 전달해야 할 인수가 있으면 이를 스택에 복사한다.
    5. 레지스터를 초기화하고 스택 포인터는 사용 가능한 첫 주소를 가르킨다.
    6. start-up routine 으로 점프한다. 인수를 인수 레지스터에 넣고프로그램의 main을 호출한다.main에서 return하면 exit 시스템 호출을 사용하여 프로그램을 종료시킨다.

    Dynamic Linking

  • 앞에서 설명한 전통적인 library link 방식은 여러 불편함이 있어 대체로 나온것이 동적 링크 라이브러리(DLL)이다.

  • 초기 DLL
    <stdio.h>를 부르면 필요한 것만 링킹하는게 아니라 전체다 링킹함, 메모리 소모 크다.

  • lazy Linkage(초기 DLL 개선)
    library에서 필요한 것만 골라씀, 메모리 소모 적다.

    Relocating Code and Data


C Sort Example

C code:

void swap(int v[] int k)
{
	int temp;
    temp = v[k];
    v[k] = v[k + 1];
    v[k+1] = temp;
}

MIPS:

sll $t1,$a1,2   // reg t1 = k * 4
add $t1,$a0,$t1 // t1 = v + (k * 4)
lw  $t0,0($t1)  // t0(temp) = v[k]
lw  $t2,4($t1)  // t2 = v[k + 1]
sw  $t2,0($t1)  // v[k](t1) = v[k + 1](t2)
sw  $t0,4($t1)	// v[k+1](t1+4) = t0(temp)

0개의 댓글