web-dev-qa-db-ja.com

リンカスクリプトでKEEPとはどういう意味ですか?

LDマニュアル は、KEEPコマンドが何をするかを説明していません。以下は、KEEPを特徴とするサードパーティのリンカースクリプトの抜粋です。 KEEPコマンドはldで何をしますか?

SECTIONS
{  
    .text :
    {
        . = ALIGN(4);
        _text = .;
        PROVIDE(stext = .);
        KEEP(*(.isr_vector))
        KEEP(*(.init))
        *(.text .text.*)        
        *(.rodata .rodata.*)        
        *(.gnu.linkonce.t.*)
        *(.glue_7)
        *(.glue_7t)
        *(.gcc_except_table)
        *(.gnu.linkonce.r.*)
        . = ALIGN(4);
        _etext = .;
        _sidata = _etext;
        PROVIDE(etext = .);   
            _fini = . ;
                *(.fini)

    } >flash
43
Randomblue

Afaik LDは、シンボルが参照されていない場合でも、セクション内のシンボルを保持します。(-gc-sections)。

通常、バイナリスタートアッププロセスで特別な意味を持つセクションに使用され、依存ツリーのルートをマークします。


(以下のSabuncuの場合)

依存ツリー

未使用のコードを削除する場合、コードを分析し、すべての到達可能なセクション(コード+グローバル変数+定数)をマークします。

そのため、セクションを選択して「使用済み」とマークし、そのセクションが参照する他のセクションを確認してから、それらのセクションを「使用済み」とマークし、参照先などを確認します。

「使用済み」とマークされていないセクションは冗長になり、削除できます。

セクションは複数の他のセクション(たとえば、3つの異なる他のセクションを呼び出す1つのプロシージャ)を参照できるため、結果を描画する場合はツリーを取得します。

ルート:

ただし、上記の原則には問題があります。常に使用される「最初の」セクションは何ですか?いわば、ツリーの最初のノード(ルート)です。これが "keep()"が行うことで、どのセクション(利用可能な場合)を最初に調べるかをリンカーに伝えます。結果として、これらは常にリンクされています。

通常、これらは、動的リンクに関連するタスクを実行するためにプログラムローダーから呼び出されるセクション(オプション、OS /ファイル形式に依存)、およびプログラムのエントリポイントです。

42

その使用法を示す最小限のLinux IA-32の例

main.S

.section .text
.global _start
_start:
    /* Dummy access so that after will be referenced and kept. */
    mov after, %eax
    /*mov keep, %eax*/

    /* Exit system call. */
    mov $1, %eax

    /* Take the exit status 4 bytes after before. */
    mov $4, %ebx
    mov before(%ebx), %ebx

    int $0x80

.section .before
    before: .long 0
/* TODO why is the `"a"` required? */
.section .keep, "a"
    keep: .long 1
.section .after
    after: .long 2

link.ld

ENTRY(_start)
SECTIONS
{
    . = 0x400000;
    .text :
    {
        *(.text)
        *(.before)
        KEEP(*(.keep));
        *(.keep)
        *(.after)
    }
}

コンパイルして実行

as --32 -o main.o main.S
ld --gc-sections -m elf_i386 -o main.out -T link.ld main.o
./main.out
echo $?

出力

1

KEEP行をコメントアウトすると、出力は次のようになります。

2

どちらか:

  • ダミーmov keep, %eaxを追加します
  • --gc-sectionsを削除

出力は1に戻ります。

Ubuntu 14.04、Binutils 2.25でテスト済み。

説明

シンボルkeepへの参照はないため、セクション.keepが含まれます。

したがって、ガベージコレクションが有効になっており、KEEPを使用して例外を作成しない場合、そのセクションは実行可能ファイルに配置されません。

beforeのアドレスに4を追加するため、keepセクションが存在しない場合、終了ステータスは2になり、次の.after セクション。

TODO:"a".keepから削除しても何も起こりません。これにより、割り当て可能になります。その理由はわかりません。そのセクションは.textセグメント内に配置されます。これは、マジック名のために割り当て可能です。

リンカに特定のセクションを保持させる

SECTIONS 
{
....
....

*(.rodata .rodata.*)

KEEP(*(SORT(.scattered_array*)));
}
1
leesagacious