64 ビット FreeBSD で C アプリケーションをコンパイルしようとすると、次のエラーが発生しました。
再配置 R_X86_64_32S は、共有オブジェクトを作成するときに使用できません。-fPIC で再コンパイル
R_X86_64_32S
移転とはR_X86_64_64
?
エラーについてグーグルで検索しましたが、考えられる原因です-R_X86_64_32Sが実際に何を意味するのか誰かが教えてくれれば幸いです。
64 ビット FreeBSD で C アプリケーションをコンパイルしようとすると、次のエラーが発生しました。
再配置 R_X86_64_32S は、共有オブジェクトを作成するときに使用できません。-fPIC で再コンパイル
R_X86_64_32S
移転とはR_X86_64_64
?
エラーについてグーグルで検索しましたが、考えられる原因です-R_X86_64_32Sが実際に何を意味するのか誰かが教えてくれれば幸いです。
R_X86_64_32S
およびR_X86_64_64
は、amd64アーキテクチャ用にコンパイルされたコードの再配置タイプの名前です。それらすべてをamd64ABIで調べることができます。それによると、R_X86_64_64
に分解されます:
とR_X86_64_32S
:
これは基本的に、どちらの場合も「この再配置によって示されるシンボルの値と加数」を意味します。次に、リンカはR_X86_64_32S
、生成された値が元の64ビット値に符号拡張されていることを確認します。
これで、実行可能ファイルで、コードセグメントとデータセグメントに指定された仮想ベースアドレスが与えられます。実行可能コードは共有されず、各実行可能ファイルは独自の新しいアドレス空間を取得します。これは、コンパイラがデータセクションがどこにあるかを正確に認識し、それを直接参照できることを意味します。一方、ライブラリは、データセクションがベースアドレスから指定されたオフセットにあることだけを知ることができます。そのベースアドレスの値は、実行時にのみ知ることができます。したがって、すべてのライブラリは、位置に依存しないコード(または略してPIC)と呼ばれる、メモリ内のどこに配置されても実行できるコードで作成する必要があります。
今、あなたの問題を解決することになると、エラーメッセージはそれ自体を物語っています。
これを理解するには、まず次のことを行う必要があります。
基準
R_X86_64_64
、R_X86_64_32
およびR_X86_64_32S
これらはすべて、ELF ファイル形式の AMD64 仕様を含むSystem V AMD ABIによって定義されています。
これらはすべて、ELF 形式のアーキテクチャに依存しない部分を指定するSystem V ABI 4.1 (1997)ELF32_R_TYPE
で指定されている、再配置エントリのフィールドの可能な値です。その標準はフィールドのみを指定しますが、アーキテクチャに依存する値は指定しません。
4.4.1「再配置タイプ」の下に、要約表が表示されます。
Name Field Calculation
------------ ------ -----------
R_X86_64_64 word64 A + S
R_X86_64_32 word32 A + S
R_X86_64_32S word32 A + S
このテーブルについては後で説明します。
そしてメモ:
R_X86_64_32
および再配置はR_X86_64_32S
、計算された値を 32 ビットに切り捨てます。リンカは、R_X86_64_32 (R_X86_64_32S) 再配置用に生成された値が元の 64 ビット値にゼロ拡張 (符号拡張) されていることを確認する必要があります。
R_X86_64_64 と R_X86_64_32 の例
R_X86_64_64
最初にand を見てみましょうR_X86_64_32
:
.section .text
/* Both a and b contain the address of s. */
a: .long s
b: .quad s
s:
それで:
as --64 -o main.o main.S
objdump -dzr main.o
内容:
0000000000000000 <a>:
0: 00 00 add %al,(%rax)
0: R_X86_64_32 .text+0xc
2: 00 00 add %al,(%rax)
0000000000000004 <b>:
4: 00 00 add %al,(%rax)
4: R_X86_64_64 .text+0xc
6: 00 00 add %al,(%rax)
8: 00 00 add %al,(%rax)
a: 00 00 add %al,(%rax)
Ubuntu 14.04、Binutils 2.24 でテスト済み。
ここでは逆アセンブルを無視し (これはデータであるため意味がありません)、ラベル、バイト、および再配置のみを調べます。
最初の移転:
0: R_X86_64_32 .text+0xc
つまり:
0
a
: バイト 0 (ラベル)に作用するR_X86_64_
: AMD64 システム V ABI のすべての再配置タイプで使用されるプレフィックス32
: (4 バイト)のみを指定したため、ラベルの 64 ビット アドレスはs
32 ビット アドレスに切り捨てられます。.long
.text
:私たちは.text
セクションにいます0xc
: これは、再配置エントリのフィールドである加数です。移転先の住所は次のように計算されます。
A + S
どこ:
A
: ここに加数0xC
S
: ここでは再配置前のシンボルの値00 00 00 00 == 0
したがって、再配置後、新しいアドレスはセクションの 0xC == 12 バイトになり.text
ます。
(4 バイト) と(8 バイト)のs
後に来るので、これはまさに私たちが期待するものです。.long
.quad
R_X86_64_64
は類似していますが、ここでは のアドレスを切り詰める必要がないため、より単純ですs
。これは、カラムではword64
なく標準スルーで示されます。word32
Field
R_X86_64_32S 対 R_X86_64_32
R_X86_64_32S
vsの違いR_X86_64_32
は、リンカーが「収まるように再配置が切り捨てられた」と文句を言うときです。
32
: 再配置後に切り捨てられた値が古い値をゼロ拡張しない場合、つまり、切り捨てられたバイトはゼロでなければならない場合に文句を言います:
例:がゼロではないため、苦情FF FF FF FF 80 00 00 00
を生成します。80 00 00 00
FF FF FF FF
32S
: 再配置後の切り捨てられた値が古い値を拡張しない場合に文句を言います。
例:の最後のビットと切り捨てられたビットはすべて 1であるため、 FF FF FF FF 80 00 00 00
toは問題ありません。80 00 00 00
80 00 00 00
参照:この GCC エラー "... relocation truncated to fit..." とはどういう意味ですか?
R_X86_64_32S
次の方法で生成できます。
.section .text
.global _start
_start:
mov s, %eax
s:
それで:
as --64 -o main.o main.S
objdump -dzr main.o
与えます:
0000000000000000 <_start>:
0: 8b 04 25 00 00 00 00 mov 0x0,%eax
3: R_X86_64_32S .text+0x7
32S
これで、リンカー スクリプトに合わせて切り捨てられた「再配置」を確認できます。
SECTIONS
{
. = 0xFFFFFFFF80000000;
.text :
{
*(*)
}
}
今:
ld -Tlink.ld a.o
次の理由で問題ありません:は符号拡張である0xFFFFFFFF80000000
に切り捨てられます。80000000
しかし、リンカー スクリプトを次のように変更すると:
. = 0xFFFF0FFF80000000;
エラーが生成さ0
れるようになりました。これは、符号拡張ではなくなったためです。
32S
メモリ アクセスに使用するがイミディエイト32
に使用する理由:アセンブラーが R_X86_64_32 のようなゼロ拡張ではなく、R_X86_64_32S のような符号拡張再配置を使用する方が良いのはいつですか?
R_X86_64_32S および PIE (位置に依存しない実行可能ファイル)
R_X86_64_32S は位置に依存しない実行可能ファイルでは使用できませんgcc -pie
。
relocation R_X86_64_32S against `.text' can not be used when making a PIE object; recompile with -fPIC
l
私はそれを説明する最小限の例を提供しました: What is the -fPIE option for position-independent executables in gcc and ld?
つまり、必要に応じて-fPIC
フラグを使用せずに共有オブジェクトをコンパイルしたことを意味します。
gcc -shared foo.c -o libfoo.so # Wrong
電話する必要があります
gcc -shared -fPIC foo.c -o libfoo.so # Right
ELF プラットフォーム (Linux) では、共有オブジェクトは位置に依存しないコード (メモリ内の任意の場所から実行できるコード) でコンパイルされます。このフラグが指定されていない場合、生成されるコードは位置に依存するため、この共有オブジェクトを使用することはできません。物体。
この問題に遭遇し、この回答が役に立たないことがわかりました。静的ライブラリを共有ライブラリとリンクしようとしていました。-fPIC スイッチをコマンドラインの前に置くことも調査しました(他の回答でアドバイスされているように)。私にとって、問題を解決した唯一のことは、静的ライブラリを共有に変更することでした。-fPIC に関するエラー メッセージは、さまざまな原因で発生する可能性があると思いますが、基本的には、ライブラリがどのように構築されているかを確認し、さまざまな方法で構築されているライブラリを疑ってください。