webentwicklung-frage-antwort-db.com.de

Was bedeutet dieser GCC-Fehler "... Umzug abgeschnitten, um zu passen ..."?

Ich programmiere die Host-Seite eines Host-Accelerator-Systems. Der Host läuft auf dem PC unter Ubuntu Linux und kommuniziert über eine USB-Verbindung mit der Embedded-Hardware. Die Kommunikation erfolgt durch Kopieren von Speicherblöcken in den und aus dem Speicher der eingebetteten Hardware.

Im Speicher der Karte befindet sich ein Speicherbereich, den ich als Mailbox verwende, in der ich die Daten schreibe und lese. Das Postfach ist als Struktur definiert, und ich verwende dieselbe Definition, um ein Spiegelpostfach in meinem Host-Bereich zuzuweisen.

Ich habe diese Technik in der Vergangenheit erfolgreich angewendet, und jetzt habe ich das Host Eclipse-Projekt in den Arbeitsbereich meines aktuellen Projekts kopiert und die entsprechenden Namensänderungen vorgenommen. Das Seltsame ist, dass ich beim Erstellen des Host-Projekts jetzt die folgende Meldung erhalte:

Gebäudeziel: fft2d_Host
Aufruf von: GCC C Linker
gcc -L/opt/adapteva/esdk/tools/Host/x86_64/lib -o "fft2d_Host" ./src/fft2d_Host.o -le_Host -lrt

./src/fft2d_Host.o: In der Funktion "main":

fft2d_Host.c :(. text + 0x280): Verschiebung abgeschnitten, um zu passen: R_X86_64_PC32 gegen das Symbol `Mailbox ', das im Abschnitt COMMON in ./src/fft2d_Host.o definiert ist

Was bedeutet dieser Fehler und warum baut er nicht auf dem aktuellen Projekt auf, während er mit dem älteren Projekt in Ordnung ist?

49
ysap

Sie versuchen, Ihr Projekt so zu verknüpfen, dass das Ziel eines relativen Adressierungsschemas weiter entfernt ist, als dies durch die 32-Bit-Verschiebung des ausgewählten relativen Adressierungsmodus unterstützt werden kann. Dies kann daran liegen, dass das aktuelle Projekt größer ist, dass Objektdateien in einer anderen Reihenfolge verknüpft werden oder dass ein unnötig umfangreiches Zuordnungsschema vorhanden ist.

Diese Frage ist ein perfektes Beispiel dafür, warum es oftmals produktiv ist, eine Websuche im allgemeinen Teil einer Fehlermeldung durchzuführen.

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

Welches bietet einige heilende Vorschläge.

46
Chris Stratton

Minimales Beispiel, das den Fehler erzeugt

main.S: Verschiebt eine Adresse in %eax (32-Bit):

_start:
    mov $_start, %eax

linker.ld:

SECTIONS
{
    /* This says where `.text` will go in the executable. */
    . = 0x100000000;
    .text :
    {
        *(*)
    }
}

Kompilieren Sie auf x86-64:

as -o main.o main.S
ld -o main.out -T linker.ld main.o

Ergebnis von ld:

(.text+0x1): relocation truncated to fit: R_X86_64_32 against `.text'

Denk daran, dass:

  • as fügt alles in den .text ein, wenn kein anderer Abschnitt angegeben ist
  • ld verwendet den .text als Standardeinstiegspunkt, wenn ENTRY. Somit ist _start Das allererste Byte von .text.

So beheben Sie das Problem: Verwenden Sie stattdessen linker.ld Und subtrahieren Sie von Anfang an 1:

SECTIONS
{
    . = 0xFFFFFFFF;
    .text :
    {
        *(*)
    }
}

Anmerkungen:

  • in diesem Beispiel können wir _start nicht mit .global _start global machen, da es sonst immer noch fehlschlägt. Ich denke, das passiert, weil globale Symbole Ausrichtungsbeschränkungen haben (0xFFFFFFF0 Funktioniert). TODO Wo ist das im ELF-Standard dokumentiert?

  • das Segment .text hat auch eine Ausrichtungsbeschränkung von p_align == 2M. Unser Linker ist jedoch intelligent genug, um das Segment auf 0xFFE00000 Zu setzen, mit Nullen bis 0xFFFFFFFF Zu füllen und e_entry == 0xFFFFFFFF Einzustellen. Dies funktioniert, erzeugt jedoch eine übergroße ausführbare Datei.

Getestet unter Ubuntu 14.04 AMD64, Binutils 2.24.

Erklärung

Zunächst müssen Sie anhand eines minimalen Beispiels verstehen, was Umzug ist: https://stackoverflow.com/a/30507725/895245

Schauen Sie sich als nächstes objdump -Sr main.o An:

0000000000000000 <_start>:
   0:   b8 00 00 00 00          mov    $0x0,%eax
                        1: R_X86_64_32  .text

Wenn wir uns ansehen, wie Anweisungen im Intel-Handbuch codiert sind, sehen wir Folgendes:

  • b8 Sagt, dass dies ein mov für %eax Ist
  • 0 Ist ein sofortiger Wert, der nach %eax Verschoben werden soll. Der Umzug ändert ihn dann so, dass er die Adresse von _start Enthält.

Beim Verschieben in 32-Bit-Register muss das unmittelbare Bit ebenfalls 32-Bit sein.

Aber hier muss die Verlagerung diese 32-Bit ändern, um die Adresse von _start In sie zu setzen, nachdem die Verknüpfung erfolgt ist.

0x100000000 Passt nicht in 32-Bit, aber 0xFFFFFFFF Passt. Also der Fehler.

Dieser Fehler kann nur bei Verschiebungen auftreten, die Kürzungen verursachen, z. R_X86_64_32 (8 Byte bis 4 Byte), jedoch niemals auf R_X86_64_64.

Und es gibt einige Arten von Umzügen, die eine Erweiterung sign anstelle einer Erweiterung von Null erfordern, wie hier gezeigt, z. R_X86_64_32S. Siehe auch: https://stackoverflow.com/a/33289761/895245

Denken Sie daran, die Fehlermeldungen der Reihe nach zu behandeln. In meinem Fall war der Fehler darüber "undefinierte Referenz", und ich habe ihn visuell übersprungen, um den interessanteren Fehler "Umzug abgeschnitten" zu finden. In der Tat war mein Problem eine alte Bibliothek, die die Meldung "undefinierte Referenz" verursachte. Sobald ich das behoben hatte, verschwand der "Umzug abgeschnitten" ebenfalls.

10
Barton

Ich bin auf dieses Problem gestoßen, als ich ein Programm erstellt habe, das sehr viel Stapelspeicher benötigt (über 2 GiB). Die Lösung bestand darin, das Flag -mcmodel=medium , das sowohl von GCC- als auch von Intel-Compilern unterstützt wird.

10
Rufflewind

Oft bedeutet dieser Fehler Ihr Programm ist zu groß und oft ist es zu groß, weil es ein oder mehrere sehr große Datenobjekte enthält. Beispielsweise,

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

wird unter x86-64/Linux einen Fehler "Umzug zugeschnitten, um zu passen" erzeugen, wenn er im Standardmodus und ohne Optimierung kompiliert wird. (Wenn Sie die Optimierung einschalten, könnte zumindest theoretisch herausgefunden werden, dass large_array ist unbenutzt und/oder dass other_global wird nie geschrieben und generiert daher Code, der das Problem nicht auslöst.)

Standardmäßig verwendet GCC für diese Architektur ein "kleines Codemodell", bei dem der gesamte Code des Programms und die statisch zugewiesenen Daten in die niedrigsten 2 GB des Adressraums passen müssen. (Die genaue Obergrenze liegt bei etwa 2 GB - 2 MB, da die niedrigsten 2 MB des Adressraums eines Programms dauerhaft unbrauchbar sind. Wenn Sie eine gemeinsam genutzte Bibliothek oder eine positionsunabhängige ausführbare Datei kompilieren, müssen der gesamte Code und die Daten immer noch in zwei passen Gigabyte, aber sie sind nicht mehr an den unteren Rand des Adressraums genagelt.) large_array verbraucht den ganzen Platz für sich, also other_global wird eine Adresse zugewiesen, die über dem Grenzwert liegt, und der für main generierte Code kann sie nicht erreichen. Sie erhalten einen kryptischen Fehler vom Linker und keinen hilfreichen "large_array ist zu groß "Fehler vom Compiler, weil der Compiler in komplexeren Fällen nicht wissen kann, dass other_global ist nicht in Reichweite, es wird also nicht einmal versucht, die einfachen Fälle zu lösen.

In den meisten Fällen besteht die richtige Antwort auf diesen Fehler darin, Ihr Programm so umzugestalten, dass es keine riesigen statischen Arrays und/oder Gigabytes an Maschinencode benötigt. Wenn Sie sie jedoch aus irgendeinem Grund wirklich benötigen, können Sie die "mittlere" oder "große" Codemodelle verwenden, um die Grenzen zu heben, zum Preis einer etwas weniger effizienten Codegenerierung. Diese Codemodelle sind x86-64-spezifisch. Ähnliches gilt für die meisten anderen Architekturen, aber die genauen "Modelle" und die damit verbundenen Grenzen variieren. (Auf einer 32-Bit-Architektur verfügen Sie beispielsweise möglicherweise über ein "kleines" Modell, bei dem die Gesamtmenge an Code und Daten auf 2 beschränkt war24 Bytes.)

9
zwol

Auf Cygwin -mcmodel=medium ist bereits voreingestellt und hilft nicht. Füge ich hinzu, -Wl,--image-base -Wl,0x10000000 to GCC Linker hat den Fehler behoben.

9
midenok