エラーを生成する最小限の例
main.S
アドレスを%eax
(32ビット)に移動します。
main.S
_start:
mov $_start, %eax
リンカー.ld
SECTIONS
{
/* This says where `.text` will go in the executable. */
. = 0x100000000;
.text :
{
*(*)
}
}
x86-64でコンパイルします。
as -o main.o main.S
ld -o main.out -T linker.ld main.o
の結果ld
:
(.text+0x1): relocation truncated to fit: R_X86_64_32 against `.text'
それを念頭に置いて:
as
.text
他のセクションが指定されていない場合は、すべてを配置します
ld
.text
の場合、デフォルトのエントリポイントとしてを使用しますENTRY
。したがって_start
、はの最初のバイトです.text
。
修正方法:linker.ld
代わりにこれを使用し、最初から1を引きます。
SECTIONS
{
. = 0xFFFFFFFF;
.text :
{
*(*)
}
}
ノート:
_start
この例では、を使用してグローバルにすることはできません.global _start
。そうしないと、失敗します。これは、グローバルシンボルに配置の制約があるために発生すると思います(0xFFFFFFF0
機能します)。TODOそれはELF標準でどこに文書化されていますか?
.text
セグメントには、の配置制約もありますp_align == 2M
。0xFFE00000
しかし、私たちのリンカは、セグメントをに配置し、までゼロで埋めて0xFFFFFFFF
設定するのに十分賢いe_entry == 0xFFFFFFFF
です。これは機能しますが、特大の実行可能ファイルを生成します。
Ubuntu 14.04 AMD64、Binutils2.24でテスト済み。
説明
まず、最小限の例で再配置とは何かを理解する必要があります:https ://stackoverflow.com/a/30507725/895245
次に、見てみましょうobjdump -Sr main.o
:
0000000000000000 <_start>:
0: b8 00 00 00 00 mov $0x0,%eax
1: R_X86_64_32 .text
インテルのマニュアルで指示がどのようにエンコードされているかを調べると、次のことがわかります。
b8
mov
これは%eax
0
に移動する即時値%eax
です。次に、再配置により、のアドレスが含まれるように変更されます_start
。
32ビットレジスタに移動する場合、イミディエートも32ビットである必要があります。
_start
ただし、ここでは、リンクが発生した後、再配置によって32ビットを変更してのアドレスを挿入する必要があります。
0x100000000
32ビットには適合しませんが、適合0xFFFFFFFF
します。したがって、エラー。
R_X86_64_32
このエラーは、切り捨て(8バイトから4バイトなど)を生成する再配置でのみ発生する可能性がありますが、では発生しませんR_X86_64_64
。
また、ここに示すように、ゼロ拡張ではなく符号拡張を必要とする再配置のタイプがいくつかありますR_X86_64_32S
。参照:https ://stackoverflow.com/a/33289761/895245
R_AARCH64_PREL32
質問:aarch64ベアメタルプログラムを作成するときに、「main.o:(。eh_frame + 0x1c):再配置が切り捨てられて「.text」に対してR_AARCH64_PREL32」になるのを防ぐ方法は?