60

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

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

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

ターゲットの構築:fft2d_host呼び出し:GCCC
リンカー
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):再配置が切り捨てられて適合:R_X86_64_PC32対./src/fft2d_host.oのCOMMONセクションで定義されたシンボル `Mailbox'

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

4

7 に答える 7

55

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

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

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

これはいくつかの治療法の提案を提供します。

于 2012-05-07T17:16:26.260 に答える
28

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

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 == 2M0xFFE00000しかし、私たちのリンカは、セグメントをに配置し、までゼロで埋めて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」になるのを防ぐ方法は?

于 2015-09-17T20:36:43.710 に答える
14

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

于 2016-06-21T03:48:38.023 に答える
11

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

于 2014-12-30T16:45:28.343 に答える
11

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

于 2016-01-31T07:03:04.143 に答える
10

多くの場合、このエラーはプログラムが大きすぎることを意味し、多くの場合、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それが到達不能になることを認識できないため、単純なケースでさえ試行しません。

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

于 2017-11-07T21:55:22.047 に答える
0

私はまったく同じ問題に遭遇しました。-fexceptionsビルドフラグなしでコンパイルした後、ファイルは問題なくコンパイルされました

于 2020-11-03T10:17:34.943 に答える