5

単純なプログラムが次のコマンドでコンパイルされた場合:

arm-none-eabi-gcc -shared -fpic -pie --specs=nosys.specs simple.c -o simple.exe

再配置エントリは次のコマンドで出力されます。

arm-none-eabi-readelf simple.exe -r

たくさんの再配置エントリ セクションがあります (以下を参照)。

-fpic / -pie フラグにより​​、コンパイラは位置に依存しない実行可能ファイルを生成するため、ローダーは問題なく実行可能イメージをどこにでも配置できるため、再配置テーブルは必要ないという単純な (そして明らかに間違った) 仮定があります。では、なぜそこに再配置テーブルがあるのでしょうか。これは、コードが実際には位置に依存しないことを示しているのでしょうか?

Relocation section '.rel.dyn' at offset 0x82d4 contains 37 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
000084a8  00000017 R_ARM_RELATIVE   
000084d0  00000017 R_ARM_RELATIVE   
00008508  00000017 R_ARM_RELATIVE   
00008510  00000017 R_ARM_RELATIVE   
0000855c  00000017 R_ARM_RELATIVE   
00008560  00000017 R_ARM_RELATIVE   
00008564  00000017 R_ARM_RELATIVE   
00008678  00000017 R_ARM_RELATIVE   
0000867c  00000017 R_ARM_RELATIVE   
0000870c  00000017 R_ARM_RELATIVE   
00008710  00000017 R_ARM_RELATIVE   
00008714  00000017 R_ARM_RELATIVE   
00008718  00000017 R_ARM_RELATIVE   
00008978  00000017 R_ARM_RELATIVE   
000089dc  00000017 R_ARM_RELATIVE   
000089e0  00000017 R_ARM_RELATIVE   
00008abc  00000017 R_ARM_RELATIVE   
00008ae4  00000017 R_ARM_RELATIVE   
00018af4  00000017 R_ARM_RELATIVE   
00018af8  00000017 R_ARM_RELATIVE   
00018afc  00000017 R_ARM_RELATIVE   
00018c04  00000017 R_ARM_RELATIVE   
00018c08  00000017 R_ARM_RELATIVE   
00018c0c  00000017 R_ARM_RELATIVE   
00018c34  00000017 R_ARM_RELATIVE   
00019028  00000017 R_ARM_RELATIVE   
000084cc  00000c02 R_ARM_ABS32       00000000   __libc_fini
0000850c  00000602 R_ARM_ABS32       00000000   __deregister_frame_inf
00008558  00001302 R_ARM_ABS32       00000000   __register_frame_info
00008568  00001202 R_ARM_ABS32       00000000   _Jv_RegisterClasses
00008664  00000d02 R_ARM_ABS32       00000000   __stack
00008668  00000a02 R_ARM_ABS32       00000000   hardware_init_hook
0000866c  00000802 R_ARM_ABS32       00000000   software_init_hook
00008670  00000502 R_ARM_ABS32       0001902c   __bss_start__
00008674  00000702 R_ARM_ABS32       00019048   __bss_end__
0000897c  00001402 R_ARM_ABS32       00000000   free
00008ac0  00000402 R_ARM_ABS32       00000000   malloc

Relocation section '.rel.plt' at offset 0x83fc contains 4 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00018be8  00000416 R_ARM_JUMP_SLOT   00000000   malloc
00018bec  00000616 R_ARM_JUMP_SLOT   00000000   __deregister_frame_inf
00018bf0  00001316 R_ARM_JUMP_SLOT   00000000   __register_frame_info
00018bf4  00001416 R_ARM_JUMP_SLOT   00000000   free
4

1 に答える 1

5

実行可能ファイルは複数のセクションで構成されています。実際の実装の詳細は異なりますが、これらは大まかに次の 4 つのグループに分類できます。

  1. 「テキスト」とも呼ばれる読み取り専用の実行可能コード
  2. 読み取り専用の定数データ (グローバル定数)
  3. (初期化済み) 読み取り/書き込みデータ (初期化子を持つグローバル変数)
  4. 初期化されていない読み書きデータ (その他のグローバル変数、0 に初期化)

位置に依存しないコードには、関数、グローバル変数、およびグローバル定数のアドレスへの参照が多数含まれています。

読み取り専用データと初期化された読み取り/書き込みデータには、関数、グローバル変数、およびグローバル定数のアドレスへの参照が含まれる場合があります。

int x;
int *y = &x; // y needs a relocation.

ローダー再配置に基づいてコードを再配置できますが、問題は 2 つだけです。

  1. 再配置は、プログラムの起動/ライブラリの読み込みに時間がかかります
  2. 再配置すると、RAM 内に変更されたテキスト セグメントのコピーが作成されます。これは、ライブラリをロードするプロセスごとに異なるため、RAM を浪費することになります。

本当の答えは次のとおりです。PIC は、すべての再配置を取り除くのではなく、テキストの再配置を取り除くことで上記の問題を解決することを目的としていました。

読み取り専用データと初期化されたデータの再配置は比較的少ないため、通常は (1.) と (2.) のどちらも問題になりません。とにかく、プロセスごとに個別のコピーが必要なため、読み書きデータの (2.) についても気にしません。実際、コンパイラがデータを位置非依存にする方法はありません。なぜなら、グローバルを要求した場合int* y = &x;、コンパイラはそこにポインタを置くしかないからです。

では、コードはどのようにして位置非依存になるのでしょうか? これはプラットフォームによって異なりますが、多くの場合、比較的非効率的な操作がいくつか含まれているか、位置に依存しない方法でデータとコードにアクセスするためのより効率的な命令で使用される最大オフセットにプロセッサが任意の制限を課しています。また、動的リンクは、一部の関数のアドレスが相対オフセットとしても知られていないことを意味します。そのため、コンパイラは実際のアドレスを含むテーブルを使用する傾向があり、コードはテーブルから実際のアドレスを検索します。GOT、TOC、PLT などさまざまな名前で知られているテーブルは、さまざまなプラットフォームでおそらく他のいくつかの名前で知られていますが、多くの再配置を伴う定数データになる可能性があります。

移転が避けられない場合は、(1.) と (2.) の問題を最小限に抑えるために、すべてを 1 か所にまとめることをお勧めします。

于 2017-03-05T10:53:50.490 に答える