preserve on call 은 함수를 호출하고 되돌아왔을때 reigster값을 유지해야 하는가 를 물어보는것이다.
a0 - a3:전달할 인수를 가지고 있는 인수 레지스터 4개
v0 - v1:반환되는 값을 갖게 되는 값 레지스터 2개
ra: 호출한 곳으로 되돌아가기 위해 복귀 주소를 가지고 잇는 레지스터 1개
호출 프로그램(caller)은 a0-a3에 전달할 인수 값 넣는다. ->
jal x(procedure label) 명령을 이용해서 프로시저x(callee)로 점프한다.->
피호출 프로그램은 계산을 끝낸후 계산 결과를 v0-v1으로 넣는다->
jr $ra 명령을 실행하여 복귀한다.
C code:
int leaf_example(int g,h,i,j)
{
int f;
f = (g + h) - (i + j)
return f
}
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
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)
또는 엑티베이션 레코드(activation record)
라고 부른다.
text: program code
static data: global variables, 상수나 기타 정적 변수, 배열은 크기가 고정 되어 있기 때문에 static data이다.
heap: malloc(C lang),new(java)
stack: automaitc storage
lui
를 통해서 상위 16 비트를 읽는다.beq $s0, $s1, L1
이 코드를 L1이 아주 멀어도 분기가 가능하도록 바꾸되 명령어 두개를 사용해라
bne $s0, $s1, L2
j L1
L2:
move $t0,$t1 -> add $t0,$t1,$zero
blt $t0,$t1, L -> slt $at, $t0, $t1
bne $at, $zero, L
header: 파일을 구성하는 각 부분의 크기와 위치를 서술한다.
text segment: 기계어 코드가 들어 있다.
static data segment: 프로그램이 종료 되기 전까지 할당 되어있는 정적 데이터와 프로그램의 요구에 따라 커졌다 작아졌다 하는 동적 데이터 두가지를 프로그램이 사용할 수 있게 한다.
relocation info: 프로그램이 메모리에 적재될 때 절대 주소에 의존하는 명령어와 데이터 워드를 표시한다.
debug info: 각 모듈이 어떻게 번역되었는지에 대한 간단한 설명이 들어 있다.
Linker
- 코드와 데이터 모듈을 메모리에 심벌 형태로 올려 놓는다.
- 데이터와 명령어 레이블의 주소를 결정한다.
- 외부 및 내부 참조를 해결한다.
Linker는 어셈블리로 만든 오브젝트 파일들을 하나의 실행파일로 묶어주는 역할을 한다.
만약에 링커가 없다면 프로시저를 한줄이라도 틀리면 전체 프로그램을 다시 컴파일하고 어셈블해야 한다.
Loader
- 진행순서
앞에서 설명한 전통적인 library link 방식은 여러 불편함이 있어 대체로 나온것이 동적 링크 라이브러리(DLL)이다.
초기 DLL
<stdio.h>를 부르면 필요한 것만 링킹하는게 아니라 전체다 링킹함, 메모리 소모 크다.
lazy Linkage(초기 DLL 개선)
library에서 필요한 것만 골라씀, 메모리 소모 적다.
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)