web-dev-qa-db-ja.com

このGCCエラー「...再配置は収まるように切り捨てられました...」とはどういう意味ですか?

ホストアクセラレータシステムのホスト側をプログラミングしています。ホストは、Ubuntu LinuxのPCで実行され、USB接続を介して組み込みハードウェアと通信します。通信は、組み込みハードウェアのメモリとの間でメモリチャンクをコピーすることにより実行されます。

ボードのメモリには、データを読み書きするメールボックスとして使用するメモリ領域があります。メールボックスは構造体として定義されており、同じ定義を使用して、ホストスペースにミラーメールボックスを割り当てています。

過去にこの手法を成功裏に使用していたので、ホストEclipseプロジェクトを現在のプロジェクトのワークスペースにコピーし、適切な名前を変更しました。奇妙なことに、ホストプロジェクトをビルドすると、次のメッセージが表示されます。

ビルドターゲット:fft2d_Host
呼び出し:GCC Cリンカー
gcc -L/opt/adapteva/esdk/tools/Host/x86_64/lib -o "fft2d_Host" ./src/fft2d_Host.o -le_Host -lrt

./src/fft2d_Host.o:関数「main」内:

fft2d_Host.c :(。text + 0x280):./src/fft2d_Host.oのCOMMONセクションで定義されたシンボル「Mailbox」に対するR_X86_64_PC32

このエラーは何を意味し、現在のプロジェクトではビルドできないのに、古いプロジェクトでは問題ないのはなぜですか?

49
ysap

選択した相対アドレッシングモードの32ビットディスプレイスメントでサポートできるよりも相対アドレッシングスキームのターゲットが遠くなるように、プロジェクトをリンクしようとしています。これは、現在のプロジェクトが大きいため、オブジェクトファイルが異なる順序でリンクされているため、または不必要に拡張的なマッピングスキームが使用されているためです。

この質問は、エラーメッセージの一般的な部分でWeb検索を行うことがしばしば生産的である理由の完璧な例です。次のようなものが見つかります。

http://www.technovelty.org/code/c/relocation-truncated.html

いくつかの治療上の提案を提供しています。

46
Chris Stratton

エラーを生成する最小限の例

main.Saddress%eax(32ビット)に移動します:

_start:
    mov $_start, %eax

linker.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は、ENTRYの場合、.textをデフォルトのエントリポイントとして使用します。したがって、_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、Binutils 2.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

Intelのマニュアルで命令がどのようにエンコードされているかを調べると、次のことがわかります。

  • b8は、これが%eaxへのmovであると言います
  • 0は、%eaxに移動する即値です。その後、再配置により、_startのアドレスが含まれるように変更されます。

32ビットレジスタに移動する場合、即値も32ビットでなければなりません。

しかし、ここでは、再配置はそれらの32ビットを変更して、リンクが発生した後に_startのアドレスをそれらに入れる必要があります。

0x100000000は32ビットに適合しませんが、0xFFFFFFFFは適合します。したがって、エラー。

このエラーは、切り捨てを生成する再配置でのみ発生します。 R_X86_64_32(8バイトから4バイト)、ただしR_X86_64_64ではありません。

そして、ここに示されているように、ゼロ拡張の代わりにsign拡張を必要とする再配置のタイプがいくつかありますR_X86_64_32S。参照: https://stackoverflow.com/a/33289761/895245

エラーメッセージに順番に取り組むことを忘れないでください。私の場合、このエラーの上のエラーは「未定義の参照」であり、それを視覚的にスキップして、より興味深い「切り捨てられた再配置」エラーを見つけました。実際、私の問題は「未定義の参照」メッセージを引き起こしていた古いライブラリでした。それを修正すると、「切り捨てられた再配置」もなくなりました。

10
Barton

膨大な量のスタックスペース(2 GiB以上)を必要とするプログラムをビルドしているときに、この問題に遭遇しました。解決策は、フラグ -mcmodel=medium 。GCCとIntelコンパイラの両方でサポートされています。

10
Rufflewind

多くの場合、このエラーはプログラムが大きすぎることを意味し、1つ以上の非常に大きなデータオブジェクトが含まれているために大きすぎることがよくあります。例えば、

char large_array[1ul << 31];
int other_global;
int main(void) { return other_global; }

x86-64/Linuxでは、最適化せずにデフォルトモードでコンパイルした場合、「再配置は収まるように切り捨てられます」エラーが発生します。 (最適化を有効にすると、少なくとも理論的には、large_arrayが未使用である、および/またはother_globalが決して書き込まれないことがわかり、問題を引き起こさないコードを生成できます。)

何が起こっているかというと、デフォルトでは、GCCはこのアーキテクチャで「小さなコードモデル」を使用します。このアーキテクチャでは、プログラムのコードと静的に割り当てられたデータはすべてアドレス空間の最低2GBに収まる必要があります。 (正確な上限は、2GB-2MBのようなものです。これは、プログラムのアドレス空間の最も低い2MBが永久に使用できないためです。共有ライブラリまたは位置に依存しない実行可能ファイルをコンパイルする場合、コードとデータはすべて2ギガバイトですが、アドレス空間の最下部には固定されていません。)large_arrayはそれだけですべての空間を消費するため、other_globalには制限を超えるアドレスが割り当てられ、 mainに到達できません。より複雑な場合、コンパイラはlarge_arrayが届かないことを知ることができないため、コンパイラからの有用な「other_globalが大きすぎます」エラーではなく、リンカから不可解なエラーを受け取ります。 、したがって、単純なケースでも試されません。

ほとんどの場合、このエラーが発生した場合の正しい対応は、巨大な静的配列やギガバイトのマシンコードを必要としないようにプログラムをリファクタリングすることです。ただし、何らかの理由で本当に必要な場合は、 "medium"または "large"コードモデル を使用して制限を解除できますが、コード生成の効率はやや低下します。これらのコードモデルはx86-64固有です。同様のことが他のほとんどのアーキテクチャにも存在しますが、「モデル」の正確なセットと関連する制限は異なります。 (たとえば、32ビットアーキテクチャでは、コードとデータの総量が2のようなものに制限された「小さな」モデルがあるかもしれません24 バイト。)

9
zwol

Cygwinでは、-mcmodel=mediumはすでにデフォルトであり、役に立ちません。 GCCリンカーに-Wl,--image-base -Wl,0x10000000を追加すると、エラーが修正されました。

9
midenok