AVR-Linkerfehler, "Verlagerung wurde abgeschnitten, um zu passen"

8

Ich versuche, einen Code für einen ATmega328 Mikro zu kompilieren, und ich möchte die Bibliotheken und den Kern von Arduino verwenden. Ich benutze CMake . Ich habe die Kernbibliothek und alle Objekte meines Codes und die Bibliotheken von Arduino kompiliert. Aber wenn es verlinkt, zeigen sie mir den folgenden Fehler.

  

... "Umlagerung abgeschnitten, um zu passen: R_AVR_13_PCREL gegen   Symbol "..." avr5 / libgcc.a "...

Ich habe durch Google gefunden , dass dies ein allgemeiner Fehler ist, aber keine Lösung für mich gearbeitet hat. Das einzige, was ich nicht tun kann, ist "-lm" und "-lc" -Flags am Ende des Linker-Satzes zu setzen, weil ich nicht weiß, wie ich es mit CMake machen kann.

BEARBEITEN : Ich habe versucht, es mit Makefile zu kompilieren, aber ich habe das gleiche Ergebnis bekommen, sogar "-lm" und "-lc" -Flags am Ende des Linkers gesetzt.

Ich stelle meine Makefile und CMake Dateien hier:

CMakeList.txt Die Haupt-CMake-Datei

%Vor%

arduino.cmake . Das wird von CMakeList.txt importiert:

%Vor%

Arduino-Core-CMake-Datei . Dies ist eine CMakeList.txt-Datei, die in libarduinocore -Verzeichnis abgelegt wird.

%Vor%

Makefile

%Vor%     
FarK 18.11.2011, 20:43
quelle

6 Antworten

11

Erklärung:

Wie die Fehlermeldung andeutet, hat das Problem mit der Verschiebung (des Codes) zu tun, die dazu führt, dass trunction auftritt. Die Nachricht kommt von dem Linker, der versucht, Codeteile an geeigneten Stellen im Programmspeicher abzubilden.

Wenn Code an einem bestimmten Ort platziert oder verschoben wird ("relocation") und wird dieser Code aus einem anderen Codeabschnitt referenziert, über JMP oder CALL (dh ein Funktionsaufruf) , die verschobene Adresse muss zur Anweisung JMP oder CALL hinzugefügt werden, die darauf verweist.

Die AVR-Geräte unterstützen zwei Arten von Sprung- / Aufrufanweisungen: JMP vs. RJMP und CALL vs. RCALL . Die R -Varianten machen Aufrufe relativ zum aktuellen Speicherort und sind sowohl bei der Verwendung des Programmspeichers als auch bei der Ausführungszeit effizienter. Dies ist jedoch mit Kosten verbunden: RJMP und RCALL können nur für Adressen im Bereich von +/- 4 kb von ihrer Position im Programmspeicher verwendet werden. Bei Geräten mit maximal 8 KB Programmspeicher ist das nie ein Problem, da der gesamte 8-KB-Bereich von jedem Ort aus über RCALL oder RJMP angesprochen werden kann.

Auf Geräten mit mehr als 8 KB Programmspeicher gilt dies jedoch nicht für alle möglichen Speicherorte. Daher wenn der Linker entscheidet, kann er den Code, der genannt wird, in den Bereich +/- 4kb von RJMP /% co_de setzen % Es wird kein Problem geben, aber wenn der Linker den Code nicht (wieder) findet, der innerhalb dieses Bereichs liegt, kann RCALL / RJMP nicht verwendet werden Um die neue Adresse des Codes zu erreichen, wird die Adresse also abgeschnitten (genau wie bei RCALL in C) und der generierte Code bricht ab.

Beachten Sie, dass dieses kann oder nicht für ein bestimmtes Projekt passieren kann, das 4kB Programmspeicher (auf Geräten mit & gt; 8kB Programmspeicher) irgendwann überschreitet, weil es hängt von der Verlagerung des benötigten Codes ab, die sich grundsätzlich mit jeder neuen hinzugefügten oder entfernten Zeile von C-Code ändern kann, mit jeder hinzugefügten Bibliothek oder sogar mit der Reihenfolge , in der die Bibliotheken oder andere enthalten sind Teile des Codes sind verlinkt (zB kann der Aufruf von "A" nach "B" funktionieren, wenn der Linker den Code wie "ABC" findet, aber fehlschlägt, wenn der Linker sich wie "ACB" verlagert).

Lösung:

Sie müssen den Compiler wissen lassen, dass er Anweisungen uint16_t value = 12345; uint8_t truncatedValue = value; / JMP anstelle der (effizienteren) Anweisungen CALL / RJMP generieren muss. In AVR Studio / Atmel Studio kann dies in den Projekteigenschaften, Toolchain, AVR / GNU C Compiler, Optimierung erfolgen. Die relevante Option ist "Verwenden Sie rjmp / rcall (begrenzter Bereich) auf & gt; 8k-Geräten (-meshort-anrufe)" , die deaktiviert sein müssen , um den genannten Fehler zu verhindern.
Wie das Etikett angibt, ist die entsprechende Befehlszeilenoption RCALL , die aus der gcc-Befehlszeilenparameterliste entfernt werden muss, um dasselbe zu erreichen, wenn gcc außerhalb der IDE aufgerufen wird.

Aktualisierung:

Um unnötige Verwirrung zu vermeiden, kann dieser Fehler dazu führen, dass -mshort-calls in avr-gcc 4.7 veraltet ist und aus 4.8 entfernt wird. Quelle: GCC 4.8 Änderungen .

Benutzer sollten jetzt stattdessen -mshort-calls verwenden, um Binärdateien zu generieren, bei denen die Aufrufoptimierungen möglich sind, aber niemals den Fehler erzeugen.

    
JimmyB 03.04.2013, 08:59
quelle
3

Ich stieß auf die Fehlermeldung "avr-gcc relocation truncation error" und gab ein Paar aus von Tagen, die es aussortieren. Kurz gesagt, scheint es einen Fehler im Linker zu geben.

Für eine schnelle Lösung, fügen Sie dies in Ihren Code im globalen Variablenbereich ein. Sie muss vielleicht ein paar verschiedene Array-Größen ausprobieren.

%Vor%

Hier ist was los ist. Die ersten 224 Bytes des Flash-Speichers sind der Interrupt Vektortabelle. Wenn ein Interrupt auftritt (wie ein Timer abläuft oder ein Byte vorhanden ist) wartet in einigen Empfangspuffer), teilt diese Tabelle dem Prozessor, welcher Code zu ausführen. In diesem Beispiel werden nicht viele Interrupts verwendet, sodass nicht verwendete Vektoren gesendet werden zu der Routine bad_interrupt (). Hier sind ein paar Zeilen aus der Vektortabelle.

%Vor%

Ein paar Dinge zu beachten

  • Die Routine bad_interrupt befindet sich unter der Adresse 0x1024
  • Die ersten Vektoren verwenden einen direkten Sprung zu 0x1024
  • Die letzten Vektoren verwenden einen relativen Sprung zu 0x1024

Die Verwendung von jmp und rjmp ist ein Artefakt des -mrelax-Compiler-Flags. Unter anderem teilt es dem Compiler mit, rjmp-Anweisungen zu verwenden wenn das Ziel nah genug ist (was +/- 4k ist). Andernfalls, Der Compiler sollte jmp verwenden. Das ist keine schlechte Sache, rjmp Anweisungen renne 1 Takt schneller und verwende 2 Bytes weniger Daten.

Ohne -relax verwendet der Compiler nur jmp-Anweisungen im Vektor Tisch und das Problem verschwindet. BTW, für unsere Zwecke, --relax ist das gleiche wie -Melax.

Das Problem ist, dass der Linker irgendwie blockiert wird. In obigem Beispiel: Wenn sich die Routine bad_interrupt an der Adresse 0x1028 befindet, Der Vektor sollte bei Adresse 0x24 in einen jmp umgewandelt werden, aber der Linker kann es aus irgendeinem Grund nicht tun. Stattdessen verlässt es die Anweisung als rjmp mit einem relativen Offset von +4098. Da der erlaubte Bereich 4096 ist, Der Offset würde auf +2 gekürzt werden, was ein schwerwiegender Fehler ist.

Der Grund warum "pad [500] PROGMEM = {0};" sollte funktionieren ist es wird zuteilen ein Stück Flash-Speicher zwischen der Vektortabelle und verschiebt bad_interrupt () weit genug entfernt von der Vektortabelle, dass der Linker nicht einmal versucht wird eine rjmp-Anweisung verwenden.

Bei der Suche im Internet scheint dies ein chronisches Problem für alle zu sein Arten von Lösungen, die manchmal funktionieren. Beliebt sind mehr / weniger PSTR ("Hallo Welt") konstruiert und verschiedene -lm -lc Optionen. Ich vermute Diese Dinge wackeln nur um Subroutinenadressen und blind herum Glück fallen sie an Orten, die funktionieren.

Unten ist der Code, den ich verwendet habe, um diesen Fehler zu isolieren.

%Vor%     
mark anderson 05.08.2013 15:55
quelle
2

Ich habe das Problem gelöst, ich habe Code umstrukturiert (ich habe fast alle globalen Variablen gelöscht) und ich habe '-lc -lm -lc' Flags zu makefile hinzugefügt. Ich nehme an, das Problem war die Code-Struktur, zu viele globale Variablen aufgrund schlechter Anpassung von einem Arduino-Code-Stil (Alle Quelldateien werden in die gleiche Datei eingefügt) Ich stelle das Makefile hier, ich hoffe es ist nützlich für jemanden:

%Vor%     
FarK 11.01.2012 14:23
quelle
2

Ich habe in den letzten paar Stunden an diesem Problem gearbeitet und es schließlich gelöst. Für mich hatte das damit zu tun, dass die avr libm.a im Linker-Befehl enthalten sein muss und ich die Math.h-Bibliothek benutzte, die von der libc.a-Bibliothek getrennt ist und nicht richtig verlinkt war .

Versuchen Sie, den Linker-Befehl so zu ändern, dass er folgendermaßen aussieht: -lc -lm am Anfang des Befehls und -lc am Ende:

%Vor%

Meine Referenz: Ссылка

    
Nathan Garabedian 28.05.2012 15:12
quelle
0

Nach einem langen Kampf wurde ich von Verlagerungsfehlern befreit  durch Hinzufügen von -lm -lc zu SET (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-lm -lc") Sie werden am Ende von CMke in link.txt angehängt Meine CMakeLists.txt

%Vor%

link.txt würde aussehen.

%Vor%     
user2195463 07.08.2015 00:33
quelle
0

Ich habe es aussortiert, indem ich die Regeln unten in meinem Makefile überlagert habe:

%Vor%     
RzR 04.08.2016 00:39
quelle