基礎実験1 UNIX・アセンブラ実習 第6

2007526

実習内容

サブルーチン呼び出しと復帰には,jsr命令,rts命令が関係します.今日の実習では,jsr命令,rts命令でのスタックエリアや各種レジスタの変化を観察し,サブルーチン呼び出しと復帰のメカニズムについて理解を深めます.

  

1.     プログラムの準備

今日の実習のために、アセンブラソースプログラムファイルmin.sを用意します。emacsを使って、下記のmin.sを入力しましょう。このmin.sは、与えられた数値データ(9,5,3,7,6,4,8の中から最小値を探し出すものである。

 


**

** 最小値を探索する

** min.s

**

        .org    0x0000

        .dc.l   0x5000

        .dc.l   start

       

        .org    0x0400

**--------------------------------------

**      メインルーチン

**--------------------------------------

start:

        move.l  #0x12345678, %d0 /* レジスタ退避を学ぶため、わざとレジスタd0に値を入れている */

        lea.l   DATA,%a1               /* サブルーチンに移る前の準備としてa1DATAのアドレスを格納 */

        jsr     MINIMUM         /* MINIMUMサブルーチンに処理を移す */

        .dc.w   0x4848

        stop    #0

 

**---------------------------------------

**      サブルーチン(最小値探索)

**      入力(引き数)  %a1:探索対象データの先頭アドレス

**      出力(戻り値)  %d1:結果(最小値)

**---------------------------------------

MINIMUM:

        movem.l %a1/%d0,-(%a7)  /* レジスタの退避(push)(a1,d0の値をスタックに保存する) */

        moveq.l #LENGTH,%d0     /* d0 = LENGTH - 1 */

        subq.w  #1,%d0

        move.w  (%a1),%d1

 

LOOP1:

        adda.w  #2,%a1          /* a2 = a2 + 2  */

        cmp.w   (%a1),%d1

        bcs     LABEL1

        move.w  (%a1),%d1

LABEL1:

        subq.w  #1,%d0

        bne     LOOP1

       

        movem.l (%a7)+,%a1/%d0  /* レジスタの復帰(pop */

        rts                    /* サブルーチン呼び出し元に戻る */

**---------------------------------------

** データエリア

**---------------------------------------

        .org    0x0500          /* データ領域の開始番地 */

        .equ    LENGTH, 7       /* データの個数 */

        DATA:   dc.w    9,5,3,7,6,4,8

 

プログラムの入力が出来たら、実行ファイルを作るためにアセンブルをしましょう。

 

              $ m68k-as min.s Enterキー>

 

エラーメッセージがなければ、68000エミュレータで実行してみましょう。

 

$ m68k-emu & Enterキー>

 

Fileメニューから、Load Programを実行し、min.absを選択してましょう。同時にMemory Viewer Program Listingのウィンドウも起動しておきましょう。

 

2.     jsr命令とrts命令とスタック領域

このプログラムは、メインルーチンとサブルーチンに分けて作られている。メインルーチンでは、サブルーチンに処理を移行する前の準備として、レジスタa1に探索対象となるデータのアドレスを格納し、その後jsr命令でサブルーチンMINIMUMに処理を移行する。サブルーチンではレジスタa1で指示されたデータ列の中から最小値を探索し、その結果をレジスタd1に格納する。そして、最後にrts命令でメインルーチンに戻ってくる。

 

 

 

 

 

 


このサブルーチン呼び出しの仕組みを理解するために、前回の実習で行ったブレークポイントおよびステップ実行を使ってみましょう。特にpc(プログラムカウンタ)と、a7(スタックポインタ)に注目しましょう(金子先生の講義資料も参照)。

ブレークポイントをメインルーチンのjsr命令の行に設定し、一度「Reset」ボタンを押した後、「Run」ボタンを押しましょう。jsr命令で停止した際、pcの値を覚えておきましょう。その後、「Step」実行で1行だけ実行し、サブルーチンに処理が移行したら、次のことを確認しましょう。

(1) pcの値がjsr命令の行のアドレスからサブルーチンの先頭行のアドレスに変わる。

(2) スタックポインタ(レジスタa7)が指すシステムスタックに、jsr命令の次の行のアドレスが格納されている。

サブルーチン終了後に、実行する行のアドレスがスタックに自動的に格納されている

 

(注意)サブルーチンを利用するためには、サブルーチンからメインルーチンに処理が戻るときのために、どこに戻れば良いのかを記憶しておく必要がある。そのため、サブルーチン終了後に実行すべき行(jsr命令の次の行)のアドレスをシステムスタック領域と呼ばれる場所に格納しておくのである。

サブルーチンの1行目「 movem.l  %a1/%d0, -(%a7)」は、「レジスタa1d0をシステムスタックに退避(push)する」という命令である。これはmove.l2回使って、レジスタa1d0をそれぞれシステムスタックにpushしても同じであるが、このmovem.lを使うと1行で複数のアドレスレジスタ・データレジスタを一度に扱うことができる(命令表p.274参照)。このサブルーチンで実際に使っているレジスタは

              a1:探索対象データのアドレスを指す

              d0:残りの探索対象データの個数

              d1:最小値(結果)

の3つである。これらのうち、レジスタd1はメインルーチンに結果を返すために使っている。一方、レジスタa1d0はサブルーチン内で値が変わってしまうため、そのままではサブルーチン呼び出し前のレジスタ値は失われてしまう。それを防ぐために、サブルーチンの初めに、システムスタック領域にレジスタの値を退避させるのである。下図は、サブルーチンの1行目を実行した後のシステムスタック領域の様子である。レジスタa1d0の値が順に退避されているのを確認しましょう。


レジスタd0

 

レジスタa1

 
 

 


サブルーチン内の最小値探索の過程は「Step」ボタンを押しながら、順次確認しましょう。最小値探索のためのループが終了した時点で、レジスタd1には答えが格納されているはずです。そして、その後、退避しておいたレジスタを復帰(pop)させます。これによりレジスタa1d0は、サブルーチン呼び出し前の値に戻っているはずです(レジスタ値を確認)。それと同時にスタックポインタ(レジスタa7’)も変化しているはずです(レジスタ値を確認)。サブルーチンの最後にrts命令によって、スタック領域に格納しておいた「戻りアドレス」をpcに復帰させることになります。このようにスタック領域は、一時的に数値やアドレスを保持しておくために使われ、特にサブルーチン処理などでは、重要な役割を果たします。

 


課題1実習中のプログラムmin.s に関して,次の設問に解答せよ

(1) ラベルLOOP1の次の行において、なぜアドレスに2を足すのかを説明せよ。

(2) プログラムminのサブルーチン中の以下の命令について、レジスタa1d0を復帰(pop)する前のスタックポインタa70x4ff0のとき、レジスタを復帰した後のa7はいくらになるか?

              movem.l   (%a7)+, %a1/%d0

(3) 実習中のプログラムminにおいて、探索対象データ中の数値「8」が格納されているメモリアドレスはいくらか。

(4) プログラムminの結果、最小値はいくらなったか。

 

 

課題2条件付分岐命令bcsの意味を説明せよ。

 

 

 


 


課題3.以下の命令が何を行っているか,なるべく分かりやすく,詳しく説明せよ.

(1)          move.w (%a0)+, %d0

 

(2)          .equ DATA, 0xabcd

              move.w #DATA, %d0

              move.b %d0, %d1

 

(3)         .equ OFF, 4

              move.l OFF(%a0), %d0

 

(4)                (各命令のCCRの変化についても説明すること)

move.w #5, %d0

sub.w #7, %d0

add.w #7, %d0

 

(5)                (各命令のCCRの変化についても説明すること)

move.w #0x7fff, %d0

add.w #0x0002, %d0

 

参考Webページ: http://www.db.is.kyushu-u.ac.jp/kaneko/as/index.html