Opecode CALL - HobbyOSs/opennask GitHub Wiki
0xE8 cw | CALL rel16
0xE8 cd | CALL rel32
ジャンプ先の表現がcw
とcd
なので、WORD/DWORDサイズで格納しないといけない。これがたぶんJMPと違う。
rel16とrel32のサイズをいかに判定するか
nasmでは以下のようにある
-
outobj.c: Fix for RIP relative addressing relocation.
- 上は64bitの際の話
-
下のように、相対アドレスを
data->size
から取り出している https://github.com/netwide-assembler/nasm/blob/5368e4579403daaf6c12165eb857893f8acfc7f8/output/legacy.c#L58-L84
機械語生成したあとCPUはどのように処理されるか
生成される機械語がcw
とcd
の違いしかなく、オペコードが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などのセクションをどれを先頭にするのかといった設定はリンカスクリプトで指定できる
- オブジェクトファイルが複数あり、そのそれぞれに