Lions' 本読み (120)

いやしかし昨日の勉強会ではずたぼろでした。読んではいますがそれが知識として脳に蓄積されない、というのは色々な意味で悲しい。とりあえずスタックフレームあたりの云々を再度確認しておく必要があるってことで csv 手続きとか cret 手続きのあたりを見てみます。
その前にまごろくさんスライドの 26 枚目から 28 枚目あたりを確認する必要あり。とその前に 21 枚目のスライドが先か。
まず main 関数の一部が以下。

sub     S6,sp
mov     $1,-10(r5)
mov     $2,-12(r5)
mov    -12(r5),(sp)
mov    -10(r5),-(sp)
jsr    pc,*$_func

このあたりが 26 枚目のスライドの部分ですね。フレームポインタからの位置なパラメータが微妙に違いますがスルー。2、1 という順で func に渡す引数をスタックに push しています (呼び出す手続きに渡す引数はスタックを使ってやりとりされる)。
で、最後の jsr ですが、24 枚目のスライドに詳細な説明があります。上の例だと

  1. pc をスタックに push
  2. pc と pc に転送 (この例だと意味は無いですね)
  3. func 手続きに jmp

という形になります。スタックの様子てきに言うと 26 枚目の #20 の状態で言うと

  • func 手続きからの戻り番地
  • 一つめの引数
  • 二つめの引数

という形になっている模様。次に 21 枚目のスライドにある func 手続きの命令を以下に引用します。

jsr     r5,csv
mov     4(r5),_c
mov     6(r5),_d
mov     _c,r0
add     _d,r0
jbr     L2
jmp     cret

スミマセン、jbr はスルーさせて下さい。27 枚目のスライドは csv 手続きにフォーカスされてますね。確認してみます。
とは言え、csv 手続きの前に jsr 命令ですね。

jsr     r5,csv
  1. r5 の値 (前のフレームポインタ) をスタックに push
  2. pc (戻り番地) を r5 に
  3. csv に jmp

これ、24 枚目のスライドの下に記述されているソレなのか。これ、スタックは 27 枚目のスライドの #21 の状態になって r5 には戻り番地が格納されてる形。
そして csv の定義が以下 (スライドは 27 枚目)。

1419 .globl     csv
1420 csv:
1421    mov     r5,r0
1422    mov     sp,r5
1423    mov     r4,-(sp)
1424    mov     r3,-(sp)
1425    mov     r2,-(sp)
1426    jsr     pc,(r0)
  • r5 の値 (戻り番地) を r0 に退避 (1421)
  • スタックポインタ (r6) の値を r5 に転送 (1422)
  • r4 の値をスタックに push (1423)
  • r3 の値をスタックに push (1424)
  • r2 の値をスタックに push (1425)

ええと、csv が r5 に退避された戻り番地を r0 に転送してますね。で、1422 で r5 と r6 が同じ位置を指す形にして r2 から r4 を退避しています。
で、1426 でどうなるか、というと

  1. pc をスタックに push
  2. pc と pc に転送 (この例だと意味は無いですね)
  3. r0 が指してる命令に jmp

なんとなくムダにスタックを消費している気もしますが、このあたりを cret が解決してくださるのかどうか。
その前に cret が呼び出される前のスタックの状態はどうなっているかというと

  • 1426 で push された PC の値
  • r2 の値
  • r3 の値
  • r4 の値
  • 直前のフレームポインタの値
  • func 手続きからの戻り番地
  • 一つめの引数
  • 二つめの引数

という形で r5 は直前のフレームポインタの値が格納されているスタックの番地を指しているはず (1422 で設定)。
これを前提に cret の定義を確認してみます。定義は以下。

1429 .globl cret
1430 cret:
1431   mov     r5,r1
1432   mov     -(r1),r4
1433   mov     -(r1),r3
1434   mov     -(r1),r2
1435   mov     r5,sp
1436   mov     (sp)+,r5
1437   rts     pc

28 枚目のスライドがこのあたりになりますね。で、フレームポインタの直上に r2 から r4 が退避されてます。ので、そこから値を復帰して 1435 にてフレームポインタの値をスタックポインタに代入しています。
で、1436 で直前フレームのフレームポインタを r5 に設定しています。で、1437 の rts ですが 25 枚目のスライドにフォローがあります。rts src は以下と等価とのこと。

  1. MOVE src,PC
  2. MOV (R6)+,src

フレームポインタの前には戻り番地が格納されていますのでそれが pc に格納されて呼び出し元に戻る、ということになりますね。

まとめとして

29 枚目のスライド、非常にありがたいです。

  • フレームポインタが指すアドレスには呼び出し元のフレームポインタが格納
  • スタックのその前には戻り番地が格納
  • さらにその前には引数が格納
  • スタックの後ろ (?) 側には r2 から r4 が退避される

レジスタが退避されなくなるのはいつ頃だったのだろう。