2020年08月26日

GNU ldのEXCLUDE_FILEの注意点

GNU ld(リンカ)には、EXCLUDE_FILE というフィルタ機能があり、特定のファイル(*.o オブジェクトファイルだけではなく、ライブラリの *.a アーカイブファイルも)を入力ファイルのワイルドカード指定から除外することができます。

この構文には単一セクションの場合は問題ありませんが、複数セクションを指定する場合に非直感的な仕様があることがわかったので紹介します。



例えば、高速小容量な SRAM と比較的低速で大容量な DRAM があるとします。この時、ユーザコード(のテキストセクション)は SRAM に置いて高速に実行したいが、大きいライブラリ(libFoo.a)は諦めて DRAM に置く場合、以下のように記述できます。
    _sram_addr = 0x20000000;
    _dram_addr = 0x80000000;
。。。
    .sram _sram_addr : {
        。。。
        *(EXCLUDE_FILE (*libFoo.a) .text )
        。。。
    }
    .dram _dram_addr : {
        。。。
        *(.text )
        。。。
    }
指定するセクションが .text 1 つの場合は、正しく動作します。しかし、例えば以下のように、テキストセクションをさらに細分化して指定した場合など、複数になると期待通りに動作しなくなります。
。。。/* !! Bad Example !! */
    .sram _sram_addr : {
        。。。
        *(EXCLUDE_FILE (*libFoo.a) .text.foo.* .text.bar.* )
        。。。
    }
    。。。
この仕様は、binutils 2.28 のドキュメントから明記されるようになったので、それ以前のドキュメントでは、セクションを 1 つ指定する例しか書かれていません。とはいえ、その直後に複数のセクションを指定する際の構文が紹介されているので、いかにも複数指定しても大丈夫なように見えて、とても紛らわしいです。

以下に、binutils 2.27 のドキュメントを抜粋します。
To exclude a list of files from matching the file name wildcard, EXCLUDE_FILE may be used to match all files except the ones specified in the EXCLUDE_FILE list. For example:

*(EXCLUDE_FILE (*crtend.o *otherfile.o) .ctors)

will cause all .ctors sections from all files except crtend.o and otherfile.o to be included.

There are two ways to include more than one section:

*(.text .rdata)
*(.text) *(.rdata)
さすがに紛らわしいと反省したのか、binutils 2.28 のドキュメントでは、以下のように、複数のセクションを記述する場合の解説が増えています。
When using EXCLUDE_FILE with more than one section, if the exclusion is within the section list then the exclusion only applies to the immediately following section, for example:

*(EXCLUDE_FILE (*somefile.o) .text .rdata) ※1(筆者追加)

will cause all `.text' sections from all files except somefile.o to be included, while all `.rdata' sections from all files, including somefile.o, will be included. To exclude the `.rdata' sections from somefile.o the example could be modified to:

*(EXCLUDE_FILE (*somefile.o) .text EXCLUDE_FILE (*somefile.o) .rdata) ※2(同様)

Alternatively, placing the EXCLUDE_FILE outside of the section list, before the input file selection, will cause the exclusion to apply for all sections. Thus the previous example can be rewritten as:

EXCLUDE_FILE (*somefile.o) *(.text .rdata) ※3(同様)

※1のように記述した場合、EXCLUDE_FILE が有効なのは、なんと .text だけであり、.rdata には効果が無いのです!
※2や※3のように書けば良いと解説されていますが、このような紛らわしい仕様の場合、複数人でメンテナンスしているうちに事故が起こり、非常にわかりにくいうちにプロジェクトが壊れてしまう恐れがあります。シンプルに
     *(EXCLUDE_FILE (*somefile.o) .text)
     *(EXCLUDE_FILE (*somefile.o) .rdata)
     *(EXCLUDE_FILE (*somefile.o) 。。。)
     。。。
のように書いた方が、間違いが起こりにくいように個人的には思えます。(また、ドキュメントを遵守するならば、明確に仕様についての言及が無い 2.27 以前は複数セクションを記述する方法は無い、と考えることもできます。)

kmckk at 16:22コメント(0)GCC | 若槻 

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード