FromNandの日記

自分的備忘録

【VMA・LMA】OSのリンカスクリプトについて思ったこと

こちらも参考にすると良い。
VMAとLMAについて - プログラマ専用SNS ミクプラ
組み込みシステムにおけるアドレスの考え方 (VMA, LMAについて) - FPGA開発日記


簡単に言うとVMAは実際に動作するときのアドレスを意識している。
つまり、プログラムが実際に参照するアドレスのことである。ジャンプ命令などのアドレスを指定する命令はVMAを基準にする。

これに対してLMAはその機械語がどの位置に配置するのかを表している。
それは、オブジェクトファイル上での位置かもしれないし、メモリに読み込んだ時の位置かもしれない。
組み込みOSなどでは、はじめにROMに読みこむときに指定されたりするらしい。


リンカスクリプト(完全ではないが)を使って例を上げてみよう。
binutilsのリンカldのリンカスクリプトでは物理アドレスはATで指定する。
この際、先にMEMORYコマンドを用いてメモリの領域を定義しておく。

MEMORY {
    rom(rx) : o = 0x000000, l = 0x100000
    ram(rwx) : o = 0x100000, l = 0x00ffff
}

SECTIONS{ 
    /* 色々 */
    .text : {
        *(.text)
    } > ram AT> rom
    /* 色々 */
}

「> ram」の部分はVMAを指定しているが、「AT> rom」の部分はLMAを指定している。
直接 ram にデータを配置できたら良いが、一般に RAM は揮発性なので、一旦 ROM に書いてからマイコン起動時にRAMにコピーをするという作業を行うことが多い。
よってはじめに読み込む番地をLMAに指定し、実行開始時にコピーされる番地(実際に動作する番地)をVMAに指定しているのだ。

実際にこのようなリンカスクリプトで実験してみるとロード時には.text領域はファイルの0x000000からおかれるが、プログラムの機械語物理アドレスを指定するものは0x100000に置かれるものとして即値が設定されている。



OSのリンカスクリプトはいわゆるアプリケーションのそれとは少し違うようだ。
大きな異なる点として「OSのリンカスクリプトではLMAが意味をなさない」という部分がある。
アプリケーションはリンカが設定したLMAを参考にローダがメモリに読み込むが、OSの場合はBIOSが第一ローダ、IPLが第二ローダとして動作するので、普通LMAを参考にしたりはしない。
しかし、VMAはOSのリンカスクリプトでも厳密に使用する必要がある。
なぜならVMAはリンカがオブジェクトファイルを再配置する際に必要な情報だからだ。


つまり、次のことが言えるだろう。
・OSのリンカスクリプトVMAだけを指定する。
・アプリケーションのリンカスクリプトVMA・LMAの両方を指定する。


と思っていたのだが...
なんだか、LMAはオブジェクトファイルをリンクする際にも使用されるみたい。
具体的に言うと、出力されるファイルのオフセット。
おそらく、展開先の物理アドレスとイメージファイルのオフセットは殆どの場合対応するから、こういった仕様になっているのだろうと思う。
あと、アプリケーションのLMAもローダによって無視されたり?しているみたいで、よくわかんねぇなぁ。