←前ページへ :  INDEX :  次へ→


4-6.サブルーチン ( Subroutine )

  サブルーチンはアルゴリズムのところで解説しているので、サブルーチンが何かはここでは省略する。

  どこから呼ばれるかわからないサブルーチンでは、戻るアドレスも変わるので、「JMP」命令を使用することはできない。(できなくはないんだけど) そこでこのような用途には「CALL」と「RET」を用いる。命令から推測できるように、「CALL」でサブルーチンにジャンプし、「RET」で元の場所に戻ってくる。元の場所に戻ってくるということは、どこかにアドレスを保存しておかなくてはならない。そのようなレジスタはないのだから、どこかのメモリーに置かれているわけである。これはスタックセグメント(SS)のスタックポインタ(SP)が指す領域に保管されている。(ちょっと違うけど)

  まず、「CALL」命令が実行されると、SPを2減らす。次に戻ってくるアドレス (CALL命令の次の命令があるアドレス)をSS:SPに保管する。そして、CALL命令のオペランドが指すアドレスにジャンプする
  イメージ的には次のような感じである

	sub	sp,2
	mov	[ss:sp],ip		
	jmp	ADDRESS

  逆に「RET」命令では、SS:SPが指す2byte(16bit)の内容のアドレスにジャンプし、 SPを2増やす。

  下記に例を示した。

START:
	mov	dl,'0'
	call	DISP
	inc	dl
	call	DISP
	inc	dl
	call	DISP
	inc	dl
	call	DISP
	inc	dl
	mov	ax,4c00h
	int	21h

DISP:
	mov	ah,2
	int	21h
	ret

  実行結果:「0123」と表示する。

  さて、ジャンプ命令では「short jmp」、「near jmp」と「far jmp」があることはすでに述べた。「CALL」も「near call」と「far call」がある。意味も書き方も同じで、「call  far [ds:1000]」のように書く。「near call」の書き方は上の例に示した通りである。

  また、サブルーチンから他のサブルーチンもしくは自分自身を呼び出しも可能である(これはよくやる)。さらに、サブルーチンから他のサブルーチンへ「jmp」したり、「jmp」で、メインプログラムに戻ってきても良いが、バグを防ぐ目的、サブルーチンの汎用性といった問題から、お勧めしない

       その他の書式  RET 9h : 関数からリターンし、即値で指定したバイト数をスタックからPOPする。

プロシージャ/ルーチンの呼び出し 【86】
【書式】
 CALL  label
 label = near/far
【フラグ】
OF DF IF TF SF ZF ?? AF ?? PF ?? CF
【動作】
この命令の直後に位置する命令のアドレス(現在のCSとIPまたはEIP)の内容をスタックにプッシュして、dest に分岐します。
near CALL
[SP+0] IPまたはEIP
far CALL
[SP+0] IPまたはEIP
[SP+2(4)] CS
【備考】
  • オペランドと実行モードに依存して分岐方法が決まります。
    near imm16,imm32, reg16,reg32, mem16,mem32
    セグメントの変更を伴わない分岐で呼び出し元へ戻るときは、RETN命令を使用します。 imm16,imm32は直後の命令のアドレスに相対の符号付きオフセット値でIP(EIP)に加算されます。 それ以外ではIP(EIP)に新しくロードされる値、または値の格納されているアドレス(間接指定)を表わします。
    far imm32,imm48,mem32,mem48
    セグメントを変更する分岐で呼び出し元へ戻るときはRETF命令を使用します。 新しくCSとIP(EIP)にロードされる値または値の格納されているアドレス(間接指定)を表わします。
    プロテクト モード
    ディスクリプタのアクセス権に依存して次の何れかとなります。
  • far CALL (同一レベル)
  • far CALL (異なるレベル)
  • タスクの切り替え
  • 通常、CALL命令に対する上記のRETN, RETF命令は、アセンブラが自動判定しますので、RET命令を記述します。
  • 32ビット セグメントからの16ビット セグメントへのCALL命令でプッシュされるのは、EIPではなくてIPの内容なので注意が必要です。

ルーチンからの復帰 【86】
【書式】
 RET  {imm16}
【フラグ】
OF DF IF TF SF ZF ?? AF ?? PF ?? CF
【動作】
スタックが16ビット属性のセグメントの場合はSPが、32ビット属性のセグメントの場合はESPがスタック ポインタとなります。
スタックから復帰アドレスをポップしてルーチンの呼び出し元へ分岐します。 nearの場合はIP(EIP)に、farの場合はCSとIP(EIP)にポップします。

オペランドが指定されていればimm16をスタックポインタに加算します。

【備考】
  • オペランドはCALL命令の直前でスタックにプッシュしたパラメータ領域(スタック フレーム)を、呼び出されたルーチン側で解放する場合に使用されます。

←前ページへ :  INDEX :  次へ→