繰り返し
ループは条件分岐にジャンプ文を足すことで実現できる
break;はジャンプすればOK
広域配列
広域に配列を確保するため配列そのものはメモリ上に配置
int sum =0, a[]={-1,2,3};
sum += a[0];
sum += a[1];
sum += a[2];は
.data
.align #aは4バイト境界とする
a: .word -1,2,3
.text
.global main
main:
move $t0,$zero
la $t1,a
lw $t2,0($t1)
add $t0,$t0,$t2
lw $t2,4($t1)
add $t0,$t0,$t2
lw $t2,8($t1)
add $t0,$t0,$t2
li $v0,1
move $a0,$t0
syscall
jr $raaの先頭アドレスを$t1に入れ、<定数の変位>($t1)で要素にアクセスする
MIPSの一般的なメモリ配置
ハードウェア側から強制されるわけではない
| 予備 | |
|---|---|
| テキストセグメント | プログラム領域(くらい) |
| 静的データ | 実行前に存在が判明しているデータセグメント 帯域変数や文字列など、 .dataで宣言するもの |
| 動的データ | mallocなどで実行時に動的に確保されるデータ |
| スタック | 関数呼び出しに関する情報や、仮引数を含む局所変数のための領域 |
| カーネル用 |
int sum = 0,a[]={-1,2,3}
for(i=0;i<3;i++) sum += a[i];main:
li $t0,0
li $t1,0 #変位
la $t2,a #基準アドレス
loop:
bge $t1,3,exit
sll $t3,$t1,2 #2ビット左シフト
add $t3,$t2,$t3 #t3に実行アドレスを格納
lw $t3,0($t3)
add $t0,$t0,$t3
addi $t1,t1,1
j loop基準アドレスを変化させて命令を削減する
main:
li $t0, 0 # sum=0
li $t1, 0 # i=0
la $t2, a # $t2=a
loop:
bge $t1, 3, exit # if i>=3 then goto exit
lw $t3, 0($t2) # $t3=*($t2)
add $t0, $t0, $t3 # sum+=$t3
addi $t1, $t1, 1 # i++ (終了判定専用)
addi $t2, $t2, 4 # $t2+=4 (次の要素のアドレスへ)
j loop終了の判定を変更して命令を削減する
main:
li $t0, 0 # sum=0
la $t2, a # p=a (aの先頭を指す)
add $t1, $t2, 12 # q=p+3 (aの末尾の次を指す)
loop:
bge $t2, $t1, exit # if p >= q then goto exit
lw $t3, 0($t2) # $t3 = *p
add $t0, $t0, $t3 # sum += $t3
addi $t2, $t2, 4 # p++
j loop文字列をコピーする
.data
from: .asciiz "abc"
to: .space 4
.text
.global main配列操作として扱う
int i;
char from[]="abc",to[4];
for(i=0;from[i]!='\0';i++){
to[i]=from[i];
}
to[i]='\0';main:
li $t0, 0 # i=0
la $t1, from # $t1=from
la $t2, to # $t2=to
loop:
add $t3Cではポインタがさすデータのサイズをコンパイラが知っているが、アセンブリの場合はプログラマがこれを管理する
MIPSのサブルーチン
jal命令によって呼び出し
このときは$raに対するジャンプがリターンに相当する
このとき$raを安全に扱うためにスタックに退避する
$raはcollee-saveレジスタ(使う前に退避して、使い終わったら元の値に復元する)
対比場所にはスタックを使うと都合がいい(FILOの都合)
MIPSではスタックを扱うとき
- メモリ領域はスタックセグメントを
- スタックポインタとして
$spを使用する $spではスタックトップ=そのデータの格納アドレスを保持- push/popはaddとload/storeによって実現する
サブルーチンを実現したことで引数や局所変数を用意できるようになれば関数を用意できる
広域変数は無限のエクステントを持つ
普通の変数はリターンとともに消滅する
MIPSによる関数定義の雛形
func:
add $sp, $sp, -(レジスタの退避領域+局所変数の領域) #メモリ領域を予約する
sw 退避するレジスタ,d1($sp)
...
sw 退避するレジスタ, dx($sp)
###関数本体、返り値は$v0へ###
lw レジスタ,d1($sp)
...
lw レジスタ,dx($sp)
add $sp,$sp,サイズ #$spを元に戻す
jr $raMIPSによる関数呼び出しの雛形
# $t,$a,$vを自身のフレームへ退避
# 第一引数から第四引数を$aに格納
# 第五引数以降はスタックへ
jal g
# addi $sp, $sp
# 退避した値を復元