Das Verständnis der Lage Zähler der GNU-Linker-Skripts
Arbeite ich an einem Uni-Projekt wo ich Schreibe software für ein Atmel SAM7S256 mikrocontroller von Grund auf. Dies ist mehr in die Tiefe als bei anderen MCUs mit denen ich gearbeitet habe vor, wie ein wissen von linker-Skripts und assembly-Sprache, die notwendig ist, diese Zeit herum.
Habe ich wirklich in der Untersuchung Beispiel-Projekte für die SAM7S-chips, um vollständig zu verstehen, wie man ein SAM7/ARM-Projekt von Grund auf neu. Ein bemerkenswertes Beispiel ist Miro Samek ist "Building Bare-Metal ARM Systems with GNU" tutorial gefunden hier (wo der code in dieser Frage ist aus). Ich habe auch verbrachte eine Menge Zeit mit dem Lesen der linker und der assembler-Dokumentation von sourceware.org.
Ich bin froh, dass ich verstehen die folgenden linker-Skript zum größten Teil. Es gibt nur eine Sache mit der location counter, das macht keinen Sinn für mich. Unten ist die linker-Skript bereitgestellt, mit dem oben genannten tutorial:
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_vectors)
MEMORY { /* memory map of AT91SAM7S64 */
ROM (rx) : ORIGIN = 0x00100000, LENGTH = 64k
RAM (rwx) : ORIGIN = 0x00200000, LENGTH = 16k
}
/* The sizes of the stacks used by the application. NOTE: you need to adjust */
C_STACK_SIZE = 512;
IRQ_STACK_SIZE = 0;
FIQ_STACK_SIZE = 0;
SVC_STACK_SIZE = 0;
ABT_STACK_SIZE = 0;
UND_STACK_SIZE = 0;
/* The size of the heap used by the application. NOTE: you need to adjust */
HEAP_SIZE = 0;
SECTIONS {
.reset : {
*startup.o (.text) /* startup code (ARM vectors and reset handler) */
. = ALIGN(0x4);
} >ROM
.ramvect : { /* used for vectors remapped to RAM */
__ram_start = .;
. = 0x40;
} >RAM
.fastcode : {
__fastcode_load = LOADADDR (.fastcode);
__fastcode_start = .;
*(.glue_7t) *(.glue_7)
*isr.o (.text.*)
*(.text.fastcode)
*(.text.Blinky_dispatch)
/* add other modules here ... */
. = ALIGN (4);
__fastcode_end = .;
} >RAM AT>ROM
.text : {
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb (NOTE: placed already in .fastcode) */
*(.glue_7t)/* glue thumb to arm (NOTE: placed already in .fastcode) */
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* global symbol at end of code */
} >ROM
.preinit_array : {
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >ROM
.init_array : {
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >ROM
.fini_array : {
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array*))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
} >ROM
.data : {
__data_load = LOADADDR (.data);
__data_start = .;
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .;
} >RAM AT>ROM
.bss : {
__bss_start__ = . ;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = .;
} >RAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
PROVIDE ( __end__ = _ebss );
.heap : {
__heap_start__ = . ;
. = . + HEAP_SIZE;
. = ALIGN(4);
__heap_end__ = . ;
} >RAM
.stack : {
__stack_start__ = . ;
. += IRQ_STACK_SIZE;
. = ALIGN (4);
__irq_stack_top__ = . ;
. += FIQ_STACK_SIZE;
. = ALIGN (4);
__fiq_stack_top__ = . ;
. += SVC_STACK_SIZE;
. = ALIGN (4);
__svc_stack_top__ = . ;
. += ABT_STACK_SIZE;
. = ALIGN (4);
__abt_stack_top__ = . ;
. += UND_STACK_SIZE;
. = ALIGN (4);
__und_stack_top__ = . ;
. += C_STACK_SIZE;
. = ALIGN (4);
__c_stack_top__ = . ;
__stack_end__ = .;
} >RAM
/* Remove information from the standard libraries */
/DISCARD/: {
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
}
Während das Beispiel (wie in der .ramvect, .fastcode und .stack-Abschnitte) gibt es symbol-Definitionen, wie __ram_start = .;
. Diese Adressen werden durch die startup-Assembler-code und-Initialisierung C-code zur Initialisierung den richtigen Ort in der MCU ' s RAM.
Was ich habe ein problem, das Verständnis, wie diese symbol-Definitionen, die das Ergebnis in die richtigen Werte zugewiesen wurden. Dies geschehen, wird das Skript korrekt ist, ich verstehe nur nicht, wie.
Ich verstehe es so, wenn Sie verwenden die Standort-Zähler in einem Abschnitt, es enthält nur einen relativen offset von der virtuellen Speicher-Adresse (VMA) der Abschnitt selbst.
So zum Beispiel in der Zeile __ram_start = .;
, würde ich erwarten, dass __ram_start zugewiesen werden, ein Wert von 0x0 - wie es zugewiesen ist, den Wert des location-counter am Anfang der .ramvect Abschnitt. Jedoch für die Initialisierung code, um korrekt zu arbeiten (das tut es), __ram_start muss immer zugewiesen, wie 0x00200000 (die Adresse für den Beginn des RAM).
Ich hätte gedacht, dies würde nur funktionieren, wenn die Zeile wurde statt __ram_start = ABSOLUTE(.);
oder __ram_start = ADDR(.ramvect);
.
Das gleiche gilt für __fastcode_start
und __stack_start__
. Sie können nicht alle sein, immer definiert als Adresse 0x0, sonst wird das Programm nicht funktionieren würde. Aber die Dokumentation hier verlinkt zu suggerieren scheint, dass das, was geschehen sollte. Hier ist das Zitat aus der Dokumentation:
Hinweis: . bezieht sich eigentlich auf den byte-offset vom Beginn der aktuellen enthaltene Objekt. Normalerweise ist dies die ABSCHNITTE Anweisung, dessen start-Adresse ist 0, daher . kann verwendet werden, als absolute Adresse. Wenn . ist in einem Abschnitt Beschreibung bezieht es sich allerdings auf den byte-offset vom Anfang des Abschnitts, nicht um eine absolute Adresse.
Also die Lage Zähler-Werte in diesen symbol-Zuordnungen werden sollte offsets aus dem entsprechenden Abschnitt VMAs. Also diese "_start" - Symbole sollten alle immer auf 0x0 gesetzt. Die brechen das Programm.
Also offensichtlich bin ich etwas fehlt. Ich nehme an, es könnte einfach sein, dass die Zuordnung der Standort-Zähler-Wert zu einem symbol (innerhalb eines Abschnitts) Ergebnisse in ABSOLUTEN() wird standardmäßig verwendet. Aber ich habe nicht in der Lage eine klare Erklärung finden überall, dass dies bestätigt.
Vielen Dank im Voraus, ob jemand kann klar dieses.
- Off-Topic: Hinweis: Es scheint einen bug in dieser linker-Skript. Wenn Sie es verwenden möchten, ändern Sie
.bss : {
zu.bss _edata : {
sonst Ihr .Daten und .fastcode-Sektionen überschrieben werden durch den BSS-Abschnitt. Überprüfen Sie die Demontage. - Danke, aber bist du dir sicher? Alles scheint zu funktionieren ok, wenn ich Globale Variablen und code-Ausführung aus dem RAM. Können Sie das etwas näher erklären, was das problem ist?
- Das war meine Erfahrung als ich .fastcode. Ich zerlegt die Ausgabe und schaute auf die linker-map (weil ich Probleme hatte mit anderen Sachen). Was ich sah, war, dass die .bss-Abschnitt hatte das exakt gleiche RAM-Adresse als die .data-Abschnitt. Dies bedeutet, dass, wenn Sie code in Ihre startup-Datei, kopiert die Daten zuerst, und dann löscht der bss anschließend mit dem mitgelieferten Adressen der data-Abschnitt werden die mit gelöscht werden der Größe des bss-Abschnitt. Ich kann nicht sicher sagen, denn es hängt von vielen Dingen ab, einschließlich der Makefile und Ihre Quellen. Versuchen Sie, die Demontage einer test-Programm.
- Überprüfen Sie bitte auch die Ausgabe für .fastcode und .ramvect, nur um sicherzugehen, dass Sie OK sind.
- Ha Ha, ich glaube, was du redest, ist genau das, was ich gebeten, über die in dieser Frage: stackoverflow.com/questions/14453996/... Tatsächlich, vielleicht auch nicht. Ich werde haben Sie einen Blick auf die map-Datei habe ich.
- Uhm.. ich kann sehen, wie kann man irren als die anderen. In meinem Fall, obwohl die Adresse von bss-Abschnitt war 0x10000000 die Adresse des Daten-Abschnitt war auch 0x10000000 (VMA, nicht der LMA). Also, sobald ich "daisy-Chain" der bss auf _edata, die VMA geändert 0x100000dc, das war das Ende meiner .fastcode Abschnitt.
- Ich habe einen Blick. Es ist schon eine Weile her, seit ich an diesem Projekt gearbeitet, aber ich denke, der code, der diese Frage basierte auf endete ohne .fastcode, .Daten oder .bss. Also, warum würde es da auch keine Probleme. Jedoch, ich habe die gleichen linker-Skript erneut für die nächste Phase des Projekts. Es war .fastcode und .bss dieser Zeit (obwohl keine .Daten). Wenn ich einen Blick in den linker-Karte .fastcode startet und endet an
0x00200040
und0x0020029C
. .Daten beginnt und endet an0x0020029C
als es leer ist. .bss startet und endet an0x0020029C
und0x00200438
. So scheint alles ok. - Das ist gut zu hören, wie ich gesehen habe viele linker-Skripte ohne "daisy-chaining" der VMA. 🙂 -Es könnte im Zusammenhang mit der version der LD auch, oder vielleicht sogar, wie es ist kompiliert. Ich bin mit GNU LD version 2.23.1.
- Nur um sicher zu sein, ich habe ein paar Globale Variablen und neu kompiliert werden. Die VMAs für .fastcode, .bss und .Daten waren alle wie erwartet und dass Sie sich nicht überlappen. Ich denke, es muss einen Unterschied zwischen unseren toolchains, ich bin mit der YAGARTO-GCC 4.7.2 und Binutils 2.23.1. EDIT: sah Gerade deinen neuen Kommentar. Ja, ich denke, du hast Recht. Interessant, dass wir die gleichen LD-version, aber es könnte zu tun mit der YAGARTO-Aspekt. Trotzdem danke für die Hilfe, es ist gut, sich zu vergewissern, dass alles funktioniert.
- Ein zusätzlicher Tipp: Wenn man assembler für Ihre .fastcode Abschnitt, sollten Sie nicht verwenden
.section .fastcode
sondern.section .fastcode,"ax",%progbits
. Denn wenn Sie nicht fügen Sie die flags, Ihr code wird nur gelegentlich aufgenommen werden (wenn Sie Glück haben). - Es gibt bereits eine Antwort auf deine Frage, aber ich denke, dass Sie herausfinden könnten viel mehr über das, was passiert in dem Skript, wenn Sie Lesen, web.eecs.umich.edu/~prabal/Lehre/eecs373-f10/Messwerte/...
- Das ist das Handbuch eine alte version von GNU ld aus einer inoffiziellen Quelle. sourceware.org/binutils/docs/ld
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich glaube, ich kann haben herausgefunden, die Antwort auf meine eigene Frage. Ich bin mir nicht sicher, ob ich im Recht bin, aber es ist die erste Erklärung, die ich in der Lage gewesen, zu denken, dass macht eigentlich Sinn. Was mich Umdenken war diese Seite der Dokumentation. Besonders dieses Zitat:
und dieses Zitat:
Ich hatte, Lesen Ihnen vor, aber dieses mal sah ich Sie aus einer neuen Perspektive.
Also ich denke, dass meine Fehlinterpretation war zu denken, dass ein symbol, wenn der zugewiesene eine relative byte-offset-Adresse, wird einfach der Wert des offset der base address Informationen verloren gehen.
Wurde basierend auf diesem Zitat aus meiner ursprünglichen Frage:
Statt, was ich jetzt verstehen geschieht, ist, dass die Basis-Adresse die Informationen gehen nicht verloren. Das symbol nicht einfach zugewiesen bekommen, den Wert der offset von der Basisadresse. Das symbol wird noch irgendwann aufgelöst wird, um eine absolute Adresse, sondern nur, wenn es keine chance gibt seine base Adresse kann sich ändern.
So, wo ich dachte, dass es so etwas wie
__stack_start__ = . ;
sollte geändert werden, um__stack_start__ = ABSOLUTE(.) ;
, die nicht arbeiten, ich jetzt denke, es ist unnötig. Was mehr ist, verstehe ich aus dem ersten Zitat in dieser Antwort, dass Sie "erneut verknüpfen" eine ELF-Datei?Also wenn ich
__stack_start__ = ABSOLUTE(.) ;
lief das linker-Skript zum erstellen der ELF executable, dann versucht zu verknüpfen und zog die .stack-Abschnitt irgendwo sonst, die__stack_start__
symbol wäre immer noch auf das gleiche absolute Adresse aus dem ersten link, und somit falsch sein.Dies ist wahrscheinlich schwer nachzuvollziehen, aber ich habe es geschrieben, so deutlich, wie ich konnte. Ich vermute, ich habe in der Nähe die richtige Idee, aber ich brauche immer noch jemanden, der tatsächlich weiß, über diese Dinge zu bestätigen oder zu verneinen.
Die Platzierung der Abschnitt ist bestimmt durch die memory-region nach der schließenden Klammer (
>RAM AT>ROM
). So die Ausführung-Adresse im RAM an 0x00200000 und folgende, aber die load-Adresse wird im ROM (flash) bei 0x00100000. Der startup-code muss kopiert die.fastcode
output-Abschnitt von seiner Last zu dessen Ausführung-Adresse, das ist, was die Symbole sind.Beachten Sie, dass diese müssen nicht bei Adresse 0, da der AT91SAM7S ordnet entweder RAM oder ROM-Adresse 0. In der Regel beginnt es mit ROM zugeordnet, und die Start-code-Schaltern, die auf RAM.
__fastcode_start
etc sind nicht0x0
. Ich weiß, dass das nicht das gewünschte Ergebnis, aber mein Verständnis der Lage Zähler sagt, dass das, was geschehen sollte. Jede dieser__xxx_start
Symbole sind gleich.
am Anfang der jeweiligen Abschnitte. Innerhalb der output-Sektion, ich bin zu der Annahme verleiten, dass.
hält nur den offset von der base VMA von diesem Abschnitt._start
Symbole. Ich weiß nicht, wie ich könnte falsch es. So ist die Dokumentation falsch?>region
Abschnitt "output" - Attribut." DieAT
ist auch irgendwo dokumentiert, aber ich erinnere mich, es war schwer zu finden und zu verstehen, wenn ich das erste habe dieses (ich schrieb ein linker-Skript für den AT91SAM7S256 2006).