■ コラム(6章のp.152に挿入)「MEMORYコマンドによるアドレス割り当ての制御」 ---------------------------------------------------------------- リンカ・スクリプトではMEMORYコマンドを使うことで,アドレス割り当てを 詳細に制御することができます.とくにVMA≠LMAを実現したい場合には, MEMORYコマンドは非常に便利です. たとえば組み込みシステムで,ROMから起動して動作させる場合に, テキスト領域はROM上に配置するが,データ領域は書き込みがあるため RAM上に配置し,ROMからRAMにコピーして利用したい場合があります. この場合,データ領域はLMAはROMですがVMAはRAMになるため, VMA≠LMAとなります. VMA≠LMAは,セクション作成時にATでLMA指定することで実現できます. たとえば以下のように書くことで,各セクションのLMAはROM上の連続する アドレスに配置し,しかしデータ領域とBSS領域は,VMAを 0xffbf20 以降の アドレスで配置することができます. -------- ここから .text : { vector.o(.data) *(.text) } .rodata : { *(.rodata) _erodata = . ; } .data 0xffbf20 : AT(_erodata) { *(.data) } .bss : { *(.bss) *(COMMON) } _end = . ; -------- ここまで これとは別に,MEMORYコマンドでアドレス割り当てする方法があります. MEMORYコマンドを利用すれば,以下のように記述することができます. -------- ここから MEMORY { vectors(r) : o = 0x000000, l = 0x000100 rom(rx) : o = 0x000100, l = 0x07ff00 ram(rwx) : o = 0xffbf20, l = 0x004000 stack(rw) : o = 0xffff00, l = 0x000000 } SECTIONS { .vectors : { vector.o(.data) } > vectors .text : { *(.text) } > rom .rodata : { *(.rodata) } > rom .data : { *(.data) } > ram AT> rom .bss : { *(.bss) *(COMMON) } > ram _end = . ; .stack : { _stack = . ; } > stack } -------- ここまで MEMORYコマンド内でrom,ramという領域を定義し, .dataセクションを「> ram AT> rom」として定義していることで, .dataセクションのVMAはramに,LMAはromに設定されます (後続の.bssセクションはその末尾に連続する形で配置されるので, やはりVMAはramに,LMAはromに設定されます). 領域として定義されたサイズを越えた場合にはリンカがエラーを出しますので, 機能拡張しているうちに知らないうちにメモリ不足になっていて, 突然システムダウンするようになってしまったという,原因を見つけにくい バグの予防にもなります. MEMORYコマンドの便利なところは,MEMORYコマンド内で各種の領域を定義 することでメモリ・マップのように扱える点です.たとえば上の例では romとramの他に,割り込みベクタとして vectors という領域を定義し, vector.o の .data セクションが vectors に配置されるように指定することで, 割り込みベクタを設定しています.また stack という領域を定義し, 領域内に _stack というシンボルを作成しています.これはプログラム側からは extern int start; char *p = (char *)&start; のようにしてリンカ・スクリプト内で定義されたスタックのアドレスを 知ることができます.これらを利用すれば,アドレス関連の定義をすべて リンカ・スクリプト内に集めて,アドレスをリンカ・スクリプトで 集中管理することができます. ----------------------------------------------------------------