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 und 0x0020029C. .Daten beginnt und endet an 0x0020029C als es leer ist. .bss startet und endet an 0x0020029C und 0x00200438. 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

InformationsquelleAutor Adam Goodwin | 2012-12-12
Schreibe einen Kommentar