l'essentiel est invisible pour les yeux

Wednesday, December 06, 2006

[Cell] オーバーレイで使用するリンカスクリプトを詳しく

[Cell] SPE上でオーバーレイプログラムを書くでオーバーレイを利用したプログラムを書いた。オーバーレイではリンカスクリプトによる処理が肝となるので、もう少し詳しくみていく。

リンカスクリプトは、-c commandfile(または、-T commandfile)で指定する。これはldのデフォルトコマンドに追加されるわけではなく全て上書きすることになるので、オーバーレイのセクション以外にもターゲットフォーマットに関して必要な全ての記述がされなければならない。

以前使ったld.script中の出力ファイルに関する指定。


OUTPUT_FORMAT("elf32-spu", "elf32-spu", "elf32-spu")
OUTPUT_ARCH(spu)
NOCROSSREFS(.olay1 .olay2)
ENTRY(_start)

SPUプログラムのBFDフォーマットにはelf32-spuを指定する。
spu-objdump -fを使用して確認することが出来る。

% spu-objdump -f spu/spu_main
spu/spu_main: file format elf32-spu
architecture: spu:256K, flags 0x00000012:
EXEC_P, HAS_SYMS
start address 0x000000c0
%

NOCROSSREFSで指定したセクション間で参照があった際に、エラーが発生する。オーバーレイのテクニックを使用する際は、二つのコードが同時にメモリ上にロードされているかどうかはわからないのでこのオプションが有効。

オーバーレイに関するセクションを抜き出したもの。

PROVIDE(__executable_start = 0x0000080);

/**** overlay sections ****/
/* overlay load address */
__overlay_region = 0x000080;
__load_start_overlay1 = 0x4000000;
.overlay1 __overlay_region(NOLOAD) : AT (__load_start_overlay1)
{ mod1/*.o(.text) }
__overlay1_size = SIZEOF (.overlay1);
__load_stop_overlay1 = __load_start_overlay1 + __overlay1_size;

__load_start_overlay2 = (__load_stop_overlay1 + 0x80 - 1) & ~(0x7F); /* alinged by 2**7 */
.overlay2 __overlay_region(NOLOAD) : AT (__load_start_overlay2)
{ mod2/*.o(.text) }
__overlay2_size = SIZEOF(.overlay2);
__load_stop_overlay2 = __load_start_overlay2 + __overlay2_size;
__overlay_region_size = MAX(SIZEOF(.overlay1), SIZEOF(.overlay2));
/**** overlay sections ****/


__overlay_regionはオーバレイモジュールを読み込む領域で0x80に指定する。オーバレイモジュールを読み込む領域を二つ指定する事もできる。

__overlay_region1 = 0x000080;
__overlay_region2 = 0x010080;


オーバレイセクションの開始アドレスと終端アドレスはそれぞれ、__load_start_secname, __load_stop_secnameというシンボルで定義される。

オーバーレイのポイントは、出力セクション型にNOLOADを指定することでメモリ上にロードしないことである。次の設定は、olay1/*.oにマッチする全てのオブジェクトの.textセクションをLMA(ロードアドレス)とVMA(仮想アドレス)を等しく設定するATキーワードを付けて__load_start_overlay1をセクションのロードアドレスに指定する。__overaly_region(NODATA)で定義済みメモリ領域にセクションを割り当てるが、メモリ上にロードしない。

.olay1 __overlay_region (NOLOAD) : AT (__load_start_overlay1)
{ olay1/*.o(.text) }


SIZEOFでセクションのサイズを取得できる。セクション1の開始アドレスとサイズから終端ロードアドレスを算出し、その次の128byte境界のアドレスをセクション.overlay2の開始アドレスとする。

__overlay1_size = SIZEOF (.overlay1);
__load_stop_overlay1 = __load_start_overlay1 + __overlay1_size;
__load_start_overlay2 = (__load_stop_overlay1 + 0x80 - 1) & ~(0x7F); /* alinged by 2**7 */


位置カウンタ(. = で指定される)をオーバーレイをロードする領域のアドレスにセクションの大きい方のサイズを加算して設定する。

__overlay_region_size = MAX(SIZEOF(.overlay1), SIZEOF(.overlay2));
/**** overlay sections ****/
. = __overlay_region + __overlay_region_size;


Cell上でのリンカスクリプトはIBMが提供するCell SDKサンプルから利用することが出来る。

参考
3. リンカスクリプト