LDで不連続領域にセクションを割り当てる

BF518のRev 0.0つきEZ-BOARDを引き当てるという不幸を演じてしまったため、TOPPERS/JSPの実装が無駄に面倒になりました。現在のところ0.1を使う人は快適に、0.0を使う人だけが苦しい実装です。つーか、0.0付きのボード、回収しろよ > ADI
Rev 0.0は、16kBの内部SRAMみっつがそれぞれ陸の孤島のごとくバラバラに存在するという素敵なメモリ配置です。TOPPERS/JSPのsample1は20kB程度のコードサイズになるため、コードを分割して配置しなければなりません。
VisualDSP++のリンカは、確か不連続領域にコードを流し込めるようになっています。これは、内部SRAMと外部SDRAMが不連続に存在するADIのDSPでは必須です。ところが、GNU LDはこういった不連続領域にコードを流し込めません。そこで、手作業で何らかの工夫をすることが必要になります。

メモリ領域

ADSP-BF518 Rev 0.0用の命令メモリを抜粋すると、以下のようになっています。

    MEM_INST_A (XR)   : ORIGIN = 0xffa00000, LENGTH = 16K
    MEM_INST_B (XR)   : ORIGIN = 0xffa08000, LENGTH = 16K
/*  MEM_INST_C (XR)   : ORIGIN = 0xffa10000, LENGTH = 16K	BF518のバンクCは16kBだが、キャッシュ用にあけておく */

アドレスが不連続になっています。領域Cはキャッシュに使うことを考えて予約領域としているのでそれほど問題ではありませんが、AとBが不連続というのはどうしようもなく痛々しい事態です。

うまくいかない例

上のような不連続領域にセクションを配置する場合、何らかの方法でばらしてやらなければなりません。TOPPERS/JSPの場合はリンク時にカーネルのコードがlibkernel.aというファイルにアーカイブされるので、それだけ引っ張り出してMEM_INST_Aに配置し、アプリケーション・コードなどをMEM_INST_Bに配置すればよいように思えます。
そこで、やってみたのが以下の方法です。

  .text           :
  {
    libkernel.a (.text .stub .text.* .gnu.linkonce.t.*)
    KEEP (libkernel.a (.text.*personality*))
  } >MEM_INST_A =0
  
  .text         :
  {
    *(EXCLUDE_FILE(libkernel.a) .text .stub .text.* .gnu.linkonce.t.*)
    KEEP (*(EXCLUDE_FILE(libkernel.a) .text.*personality*))
    /* .gnu.warning sections are handled specially by elf32.em.  */
    *(.gnu.warning)
  } >MEM_INST_B = 0

この方法はうまくいきません。「メモリ領域が足りない」という連れないメッセージが出力されるだけです。実行ファイルが生成されないので、readelfで中を覗くこともできません。
そこで、MEM_INST_B,Aのサイズを20KBくらいにして試してみると、どういうわけか、全部のコードが片方にだけ固まります。libkernel.aの.textのサイズは16kB未満なので分割できそうなものです。
実は、これは上の二つのマッピングの出力セクションが同じな前であることが問題なのです。LDは出力セクションを二つの不連続な領域にまたがって配置させることができません。したがって、上のマッピングは決してうまくいかないのです。

セクション名を変える

結局、これをきちんと働かせるにはセクション名を変えるしかありません。下のマッピングは2番目のセクション名を変えています。これでうまくいきます。

  .text           :
  {
    libkernel.a (.text .stub .text.* .gnu.linkonce.t.*)
    KEEP (libkernel.a (.text.*personality*))
  } >MEM_INST_A =0
  
  .text2         :
  {
    *(EXCLUDE_FILE(libkernel.a) .text .stub .text.* .gnu.linkonce.t.*)
    KEEP (*(EXCLUDE_FILE(libkernel.a) .text.*personality*))
    /* .gnu.warning sections are handled specially by elf32.em.  */
    *(.gnu.warning)
  } >MEM_INST_B = 0

最終的にはSDRAMに追い出すしかない

sample1のlibkernel.aの.textサイズは12kB程度です。私の場合、TOPPERS/JSPの機能はそれほど使わないのでlibkernel.aはもっと小さくなると思われます。しかし、大規模アプリケーションでTOPPERS/JSPの全機能を使う場合には、libkernel.aが内部SRAMに入らない可能性もあります。その場合、libkernel.aか、アプリケーションのいずれかをSDRAMに追い出すしかありません。命令領域Cを使えればいいのですが、libkernel.aが16kBを越えるなら、BF518 Rev 0.0では手の打ちようがなく、SDRAMに追い出すことになります。Rev 0.1以降では少しはまともになりますが、ファイルサイズがおおいなら、いっそSDRAMにアプリをおくほうがいいでしょう。