エラーを生成する最小限の例
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
インテルのマニュアルで指示がどのようにエンコードされているかを調べると、次のことがわかります。
b8movこれは%eax
0に移動する即時値%eaxです。次に、再配置により、のアドレスが含まれるように変更されます_start。
32ビットレジスタに移動する場合、イミディエートも32ビットである必要があります。
_startただし、ここでは、リンクが発生した後、再配置によって32ビットを変更してのアドレスを挿入する必要があります。
0x10000000032ビットには適合しませんが、適合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」になるのを防ぐ方法は?