LoginSignup
1
1

More than 1 year has passed since last update.

リンカのVMA(Virtual Memory Address)とLMA(Load Memory Address)の違い

Posted at

前置き

PCではなく、小さなマイコンの世界で使われます。
たいていはデフォルト設定のままでよいのですが、設定の意味を理解したい人や
特殊な設定をしたい人向けに。

本題

GNUリンカ(ld)の設定で、VMA(Virtual Memory Address)とLMA(Load Memory Address)があります。
名前からはイメージが湧きづらいですが、大雑把に言えば、RAMに変数を配置するために必要になるものです。

linker_script.ld
SECTIONS
{
    .data 0x1000: AT(0x2000)
    {

ここで0x1000がVMAで、0x2000がLMAです。
0x1000がRAMで0x2000がROM、と考えてもよいです。
どこがROMでどこがRAMか(メモリマップ)はマイコンによって決まります。
例えば、ルネサスのRL78/G13というマイコンなら、ROM 0x00000,RAM 0xFF700です。

Virtualと言ってもいわゆる仮想アドレスではなく、むしろ再配置(relocation)あるいは参照アドレスと言った方がよいと思います。
(MMUを積んでいないマイコンも多いです)
再配置というのは、プログラムのリンク時に具体的なアドレスを割り当てることで

int var = 1;
printf("var = %d\n", var);

この場合、printfは0x1000~の領域を参照します。

これに対して、LMAはデータを書き込む(焼く)アドレスを指定します。プログラムを実行する側にとっては、データが最初そのアドレスにあるという状態を意味します。

仮にこの部分だけを実行するとしたら、実行結果は

var = 0

になります。
(printfが存在すると仮定して)

varの初期値1は0x2000~の領域に存在するのであって、0x1000~にはないからです。

なので、実行時(main関数の前)にLMAからVMAにコピーするコードが必要なのですが
たいていはIDEが自動生成してくれます。
RL78のgccでは以下のようなコードが生成されます。この部分をまるっとコメントアウトすると、仮に~と書いた実行結果になります。

/* load data section from ROM to RAM */    
;; block move to initialize .data
    mov     es, #0
    movw    de, #_mdata    /* src ROM address of data section in de */
    movw    hl, #_data     /* dest start RAM address of data section in hl */

最初からRAMにロードすればいいじゃないかと思うかもしれませんが、組み込みではそうもいかないのです。
ロードするのはプログラム実行時ではなく、ROMに焼くときだからです。ROMに焼いた時点でELF情報は失われます。

また、RAMに再配置せずにROMのままにするのもよくないです。

linker_script.ld
SECTIONS
{
    .data 0x2000: AT(0x2000) /* ROM */
    {

この場合、

var = 2;
printf("var = %d\n", var);

実行結果

var = 1

ROMなので。
アクセス違反にはなりませんが(マイコンによる)、値は変わってくれません。

補足

これは初期値ありの変数に限った話で、初期値なしの変数(bss)の場合はROMに焼く必要はないので、VMA = LMA = RAMで構いません。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1