Opecode CALL - HobbyOSs/opennask GitHub Wiki

0xE8 cw | CALL rel16
0xE8 cd | CALL rel32

ジャンプ先の表現がcwcdなので、WORD/DWORDサイズで格納しないといけない。これがたぶんJMPと違う。

rel16とrel32のサイズをいかに判定するか

nasmでは以下のようにある

機械語生成したあとCPUはどのように処理されるか

生成される機械語がcwcdの違いしかなく、オペコードが0xE8で同一であるが、CPUはどうやって2つを区別しているのか?という話で、結論から書くと0x66の付与で変わる。

16 bitモードのとき

  • E8 cw = CALL rel16
  • 66 E8 cd = CALL rel32

32 bitモードのとき

  • E8 cd = CALL rel32
  • 66 E8 cw = CALL rel16

呼び出し先の関数のシグネチャーが不定のとき

  • 06_day/harib03eにCALL _inthandler21という命令がある、これを実際にアセンブルしてみると以下のようにジャンプ先のアドレスが設定されていない。実際のアドレスは未知のままということだ。
103 0000007C E8 [00000000]                                   CALL    _inthandler21
  • リンク時に、オブジェクトファイルがまとめられ、リンカはシンボル解決を行う。具体的には、_inthandler21というシンボルがどのアドレスにマップされるかを決定する。その際に、リンカは実際のアドレスをCALL命令に埋め込む(シンボル解決)
  • なので結論としては呼び出し先の関数のシグネチャーが不定のときは、とりあえず0で埋めとけばいい。

よもやま話

  • 上記のような呼び出し先のアドレスが不定の際の挙動はCALL命令だけでなくJMP命令などでも発生するようだ

  • シンボル解決のざっくりした流れ

    • リンカはシンボル解決を行うときすべてのオブジェクトファイルのセクションを見ていく
    • オブジェクトファイルAでは _inthandler21 が定まっていないが、 オブジェクトファイルBでは _inthandler21 = (0x1000) で定まっているというのはありうる
    • シグネチャの解決ができない(どこにも _inthandler21 のアドレス解決できる場所がない)、場合皆さんご存知の undefined reference to... というエラーになる
  • 微妙な疑問

    • オブジェクトファイルが複数あり、そのそれぞれに[section .text]のようにセクションが設定されていた場合どれを先頭とするのか?
    • GNU ldだと複数のオブジェクトファイルに同じ名前のセクション(例: .text)が存在する場合、リンカはデフォルトでオブジェクトファイルのリンク順序に従ってセクションを結合するらしい
    • .data, .text, .bssなどのセクションをどれを先頭にするのかといった設定はリンカスクリプトで指定できる