Bare-Metal-Startcode für die Initialisierung der Cortex M3 .bss-Region

10

Ich habe mich inspiriert von entwickelt hier einen Bare-Metal-Startcode für Arm Cortex M3 entwickelt. Ich stoße jedoch auf das folgende Problem: Angenommen, ich deklariere eine nicht initialisierte globale Variable, z. B. vom Typ unsigned char in main.c.

#include ...
unsigned char var; 
...
int main()
{
 ...
}

Dadurch beginnt die .bss-Region in STM32 f103 bei _BSS_START = 0x20000000 und endet bei _BSS_END = 0x20000001. Nun der Startcode

    unsigned int * bss_start_p = &_BSS_START; 
    unsigned int * bss_end_p = &_BSS_END;

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }

versucht, die gesamte .bss-Region auf Null zu initialisieren. Innerhalb dieser while-Schleife erhöht sich der Zeiger jedoch mit 4 Bytes, daher ist er nach einem Schritt bss_start_p = 0x20000004 immer anders als bss_end_p, was zu einer Endlosschleife usw. führt.

Gibt es dafür eine Standardlösung? Soll ich die Dimension der .bss-Region irgendwie auf ein Vielfaches von 4 "zwingen"? Oder sollte ich einen Zeiger auf vorzeichenloses Zeichen verwenden, um durch die .bss-Region zu gehen? Vielleicht so etwas wie:

    unsigned char * bss_start_p = (unsigned char *)(&_BSS_START); 
    unsigned char * bss_end_p = (unsigned char *)(&_BSS_END);

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }
```
C Marius
quelle
Verwenden Sie weniger als. Bootstraps werden aus einem bestimmten Grund in Assembly geschrieben. Zunächst einmal haben Sie ein .data-Problem erstellt. Es ist eine Henne-Ei-Sache zu verwenden / anzunehmen, dass C funktioniert. Sie verlassen sich mindestens auf .text, .bss und .data, aber Sie schreiben C-Code, der sicherstellt, dass C-Code funktioniert, und verwenden Dinge in C-Code, die a erfordern Bootstrap möglicherweise in C-Code geschrieben, der auf C-Funktion beruht.
old_timer
Der Code zum Kopieren von .data ist .bss sehr ähnlich. Wenn Sie ihn jedoch wie den obigen Code schreiben, müssen Sie .data kopieren, um .data zu kopieren.
old_timer

Antworten:

15

Wie Sie vermuten, geschieht dies, weil der vorzeichenlose int-Datentyp 4 Byte groß ist. Jede *bss_start_p = 0;Anweisung löscht tatsächlich vier Bytes des BSS-Bereichs.

Der bss-Speicherbereich muss korrekt ausgerichtet sein. Sie können einfach _BSS_START und _BSS_END so definieren, dass die Gesamtgröße ein Vielfaches von vier ist. Dies wird jedoch normalerweise dadurch erledigt, dass das Linker-Skript die Start- und Stopppositionen definieren kann.

Als Beispiel ist hier der Linker-Abschnitt in einem meiner Projekte:

.bss (NOLOAD) : ALIGN(4)
{
    __bss_start__ = .;
    *(.bss)
    . = ALIGN(4);
    __bss_end__ = .;
} >RAM

Die ALIGN(4)Aussagen kümmern sich um die Dinge.

Möglicherweise möchten Sie auch ändern

while(bss_start_p != bss_end_p)

zu

while(bss_start_p < bss_end_p).

Dies wird das Problem nicht verhindern (da Sie möglicherweise 1-3 Bytes mehr löschen, als Sie möchten), aber es könnte die Auswirkungen minimieren :)

Bitsmack
quelle
@CMarius Nach dem Nachdenken denke ich, dass Ihre Zeichenzeiger-Idee großartig funktionieren würde, obwohl sie mehr Zyklen erfordern würde. Aber ich bin nicht sicher, ob es nachfolgende Probleme mit dem nächsten nicht ausgerichteten Speicherbereich geben würde, deshalb werde ich es in meiner Antwort nicht erwähnen ...
bitsmack
1
while(bss_start_p < bss_end_p - 1)gefolgt von einem byteweisen Löschen des verbleibenden Speicherbereichs würde die letzte Sorge beseitigen.
glglgl
4

Die Standardlösung lautet memset():

#include <string.h>
memset(&_BSS_START, 0, &_BSS_END - &_BSS_START)

Wenn Sie die Standardbibliothek nicht verwenden können, müssen Sie entscheiden, ob es in Ihrem Fall in Ordnung ist, die Größe des Speicherbereichs auf 4 Byte zu runden und die Verwendung fortzusetzen unsigned int *. oder wenn Sie streng sein müssen, in welchem ​​Fall müssten Sie verwendenunsigned char * .

Wenn Sie die Größe wie in Ihrer ersten Schleife aufrunden , bss_start_pkann dies zwar größer als sein, bss_end_paber es ist einfach, einen Vergleich mit weniger als <anstelle eines Ungleichheitstests durchzuführen.

Natürlich können Sie auch den größten Teil des Speicherbereichs mit 32-Bit-Übertragungen und nur die letzten Bytes mit 8-Bit-Übertragungen füllen, aber das ist mehr Arbeit für wenig Gewinn, insbesondere hier, wenn es sich nur um einen Teil des Startcodes handelt.

ilkkachu
quelle
1
Stimmen Sie sehr mit der Verwendung von memset(). Die Ausrichtung auf 4 Bytes ist jedoch mehr oder weniger ein Muss. Warum also nicht?
Codo
3
In keiner Weise ist Form oder Gestalt die Standardlösung für den Bootstrap, um Memset zu verwenden, das ist verrückt.
old_timer
Sie verwenden nicht dieselbe Sprache, um diese Sprache zu booten
booten
2
Der Bootstrap-Code und das Linker-Skript sind sehr verheiratet. Es ist üblich, dass das Linker-Skript die .bss-Datei an mindestens einer 4-Byte-Grenze ausrichtet und dimensioniert, um die Füllung (im Bootstrap) jeweils um das 4-fache gegenüber den Byte-Anweisungen zu verbessern (unter der Annahme (mindestens) 32-Bit-Busse, was typisch für Arm ist, aber es gibt Ausnahmen)
old_timer
3
@old_timer, die Standard-C-Funktion zum Festlegen des Speichers auf einen bestimmten Wert ist memset(), und C ist das, worauf sie zu programmieren scheinen. Die einfache Implementierung von memset()ist auch so ziemlich nur diese Schleife, es ist nicht so, als ob sie von viel anderem abhängt. Da dies ein Mikrocontroller ist, gehe ich davon aus , dass es keine dynamische ist die Verknüpfung oder so geht (und Blick auf den Link, gibt es nicht, es ist nur ein Aufruf main()nach , dass Nullstellen - Schleife), so sollte der Compiler des Fallenlassens der Lage sein , memset()dort zusammen mit allen anderen Funktionen (oder um es inline zu implementieren).
ilkkachu
4

Wechseln Sie einfach !=zu <. Das ist normalerweise sowieso ein besserer Ansatz, da es sich um solche Probleme handelt.

Elliot Alderson
quelle
3

Es gibt unzählige andere Websites und Beispiele. Viele Tausende, wenn nicht Zehntausende. Es gibt die bekannten c-Bibliotheken mit Linkerskripten und Boostrap-Code, insbesondere newlib, glibc, aber es gibt auch andere, die Sie finden können. Bootstraping C mit C macht keinen Sinn.

Ihre Frage wurde beantwortet. Sie versuchen, Dinge, die möglicherweise nicht genau sind, genau zu vergleichen. Sie beginnen möglicherweise nicht an einer bekannten Grenze oder enden möglicherweise nicht an einer bekannten Grenze. Sie können also weniger als das tun, aber wenn der Code nicht mit einem exakten Vergleich funktioniert hat, bedeutet dies, dass Sie nach .bss in den nächsten Abschnitt zurückkehren, was dazu führen kann, dass schlimme Dinge passieren oder nicht. Ersetzen Sie ihn einfach durch einen weniger als isnt die Lösung.

Also hier geht TL; DR ist in Ordnung. Sie booten keine Sprache mit dieser Sprache, Sie können sicher damit durchkommen, aber Sie spielen mit dem Feuer, wenn Sie das tun. Wenn Sie nur lernen, wie man das macht, müssen Sie vorsichtig sein, nicht dummes Glück oder Fakten, die Sie noch nicht entdeckt haben.

Das Linker-Skript und der Bootstrap-Code haben eine sehr enge Beziehung, sie sind verheiratet, an der Hüfte verbunden, man entwickelt keine ohne die andere, was zu einem massiven Misserfolg führt. Und leider wird das Linker-Skript vom Linker und die Assembler-Sprache vom Assembler definiert, sodass beim Ändern von Toolchains erwartet wird, dass beide neu geschrieben werden müssen. Warum Assemblersprache? Es benötigt keinen Bootstrap, kompilierte Sprachen im Allgemeinen. C tut dies, wenn Sie die Verwendung der Sprache nicht einschränken möchten. Ich beginne mit etwas sehr Einfachem, das nur minimale Anforderungen an die Toolchain hat. Sie gehen nicht davon aus, dass .bss-Variablen Null sind (macht den Code weniger lesbar, wenn die Variable nie in dieser Sprache initialisiert wird , versuchen Sie dies zu vermeiden, gilt nicht für lokale Variablen, also müssen Sie am Ball sein, wann Sie es verwenden. Leute meiden sowieso Globals, Warum reden wir über .bss und .data? (Globale sind gut für diese Level-Arbeit, aber das ist ein anderes Thema)) Die andere Regel für die einfache Lösung ist, Variablen in der Deklaration nicht zu initialisieren, sondern im Code. Ja, es brennt mehr Flash, Sie haben im Allgemeinen viel, nicht alle Variablen werden sowieso mit Konstanten initialisiert, die am Ende Anweisungen verbrauchen.

Sie können dem cortex-m-Design entnehmen, dass sie möglicherweise gedacht haben, dass es überhaupt keinen Bootstrap-Code gibt, also keine .data- oder .bss-Unterstützung. Die meisten Leute, die Globals verwenden, können nicht ohne leben.

Ich könnte dies minimaler machen, aber ein minimales Funktionsbeispiel für alle Cortex-ms, die die Gnu-Toolchain verwenden. Ich kann mich nicht erinnern, welche Versionen Sie mit 5.xx oder so durch die aktuellen 9.xx starten können. Ich habe die Linker-Skripte irgendwo um 3 gewechselt. xx oder 4.xx als ich mehr lernte und als gnu etwas änderte, das mein erstes kaputt machte.

Bootstrap:

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

Einstiegspunkt in C-Code:

void bounce ( unsigned int );

unsigned int a;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

Linker-Skript.

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

All dies könnte kleiner sein und immer noch funktionieren. Hier wurden einige zusätzliche Dinge hinzugefügt, um es bei der Arbeit zu sehen.

optimierter Build und Link.

00000000 <_start>:
   0:   20001000
   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

00000014 <reset>:
  14:   f000 f804   bl  20 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
    ...

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Für einige Anbieter möchten Sie 0x08000000 oder 0x01000000 oder andere ähnliche Adressen verwenden, da der Flash dort zugeordnet und in einigen Startmodi auf 0x00000000 gespiegelt wird. Einige haben nur so viel Flash bei 0x00000000 gespiegelt, dass Sie möchten, dass der Vektortabellenpunkt auf dem Flash-Bereich der Anwendung nicht Null ist. Da es auf Vektortabellen basiert, funktioniert alles.

Beachten Sie zunächst, dass die Cortex-ms nur Daumen-Maschinen sind und aus irgendeinem Grund eine Daumenfunktionsadresse erzwungen haben, was bedeutet, dass das lsbit ungerade ist. Wenn Sie Ihre Werkzeuge kennen, teilen die Anweisungen .thumb_func dem gnu-Assembler mit, dass das nächste Label eine Daumenfunktionsadresse ist. Wenn Sie das +1 in der Tabelle tun, wird dies zum Scheitern führen. Versuchen Sie nicht, es richtig zu machen. Es gibt andere Gnu-Assembler-Möglichkeiten, eine Funktion zu deklarieren. Dies ist der minimale Ansatz.

   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

Es wird nicht gestartet, wenn Sie die Vektortabelle nicht richtig verstehen.

benötigen wohl nur den Stapelzeigervektor (kann dort alles einfügen, wenn Sie den Stapelzeiger selbst in Code setzen möchten) und den Rücksetzvektor. Ich habe hier ohne besonderen Grund vier gesetzt. Normalerweise setzen Sie 16, wollten aber dieses Beispiel verkürzen.

Was muss ein C-Bootstrap mindestens tun? 1. Setzen Sie den Stapelzeiger 2. Null .bss 3. Kopieren Sie .data 4. Verzweigen Sie zum C-Einstiegspunkt oder rufen Sie ihn auf

Der C-Einstiegspunkt wird normalerweise als main () bezeichnet. Einige Toolchains sehen jedoch main () und fügen Ihrem Code zusätzlichen Müll hinzu. Ich benutze absichtlich einen anderen Namen. YMMV.

Die Kopie von .data wird nicht benötigt, wenn dies alles RAM-basiert ist. Als Cortex-M-Mikrocontroller ist dies technisch möglich, aber unwahrscheinlich. Daher wird die .data-Kopie benötigt ..... wenn es .data gibt.

Mein erstes Beispiel und ein Codierungsstil besteht darin, sich nicht wie in diesem Beispiel auf .data oder .bss zu verlassen. Arm kümmerte sich um den Stapelzeiger, sodass nur noch der Einstiegspunkt aufgerufen werden muss. Ich möchte es haben, damit der Einstiegspunkt zurückkehren kann. Viele Leute argumentieren, dass Sie das niemals tun sollten. Sie könnten dies dann einfach tun:

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done

und nicht von centry () zurückkehren und keinen Handlercode zurücksetzen.

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000

Der Linker hat die Dinge dort platziert, wo wir gefragt haben. Und insgesamt haben wir ein voll funktionsfähiges Programm.

Arbeiten Sie also zuerst am Linker-Skript:

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

Hervorheben, dass die Namen rom und ram keine Bedeutung haben, sondern nur die Punkte für den Linker zwischen Abschnitten verbinden.

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

.align
.word __data_rom_start__
.word __data_start__
.word __data_end__
.word __data_size__

Fügen Sie einige Elemente hinzu, damit wir sehen können, was die Tools getan haben

void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

Fügen Sie einige Elemente hinzu, die in diesen Abschnitten platziert werden sollen. und bekomme

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000001b    andeq   r0, r0, r11, lsl r0
   c:   0000001b    andeq   r0, r0, r11, lsl r0
  10:   0000001b    andeq   r0, r0, r11, lsl r0

00000014 <reset>:
  14:   f000 f80c   bl  30 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

00000030 <centry>:
  30:   2207        movs    r2, #7
  32:   b510        push    {r4, lr}
  34:   4b04        ldr r3, [pc, #16]   ; (48 <centry+0x18>)
  36:   2007        movs    r0, #7
  38:   601a        str r2, [r3, #0]
  3a:   f7ff ffef   bl  1c <bounce>
  3e:   2000        movs    r0, #0
  40:   bc10        pop {r4}
  42:   bc02        pop {r1}
  44:   4708        bx  r1
  46:   46c0        nop         ; (mov r8, r8)
  48:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

Hier ist das Zeug, nach dem wir in diesem Experiment suchen (beachten Sie keinen Grund, Code tatsächlich zu laden oder auszuführen ... kennen Sie Ihre Werkzeuge, lernen Sie sie)

  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

Wir haben hier also gelernt, dass die Position von Variablen in Gnu-Linker-Skripten sehr empfindlich ist. Beachten Sie die Position von data_rom_start gegenüber data_start, aber warum funktioniert data_end ? Ich lasse dich das herausfinden. Ich verstehe bereits, warum man sich nicht mit Linker-Skripten herumschlagen und einfach mit der einfachen Programmierung beginnen möchte ...

Eine andere Sache, die wir hier gelernt haben, ist, dass der Linker data_rom_start für uns ausgerichtet hat und wir dort kein ALIGN (4) brauchten. Sollen wir davon ausgehen, dass das immer funktionieren wird?

Beachten Sie auch, dass es auf dem Weg nach draußen aufgefüllt wurde, wir haben 5 Bytes .data, aber es hat es auf 8 aufgefüllt. Ohne ALIGN () können wir die Kopie bereits mit Wörtern erstellen. Könnte dies auf der Grundlage dessen, was wir heute mit dieser Toolchain auf meinem Computer sehen, für die Vergangenheit und die Zukunft zutreffen? Wer weiß, auch wenn die ALIGNs regelmäßig überprüfen müssen, um sicherzustellen, dass einige neue Versionen nicht kaputt sind, werden sie dies von Zeit zu Zeit tun.

Lassen Sie uns von diesem Experiment aus sicherheitshalber fortfahren.

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   . = ALIGN(4);
   __data_end__ = .;
   } > ted AT > bob
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   . = ALIGN(4);
   __bss_end__ = .;
   } > ted
   __bss_size__ = __bss_end__ - __bss_start__;

}

Bewegen Sie die Enden nach innen, um mit dem übereinzustimmen, was andere Leute tun. Und das hat es nicht geändert:

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

noch ein schneller Test:

.globl bounce
bounce:
    nop
    bx lr

geben

0000001c <bounce>:
  1c:   46c0        nop         ; (mov r8, r8)
  1e:   4770        bx  lr
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

Es ist nicht erforderlich, zwischen Bounce und .align zu wechseln

Ohh, richtig, ich erinnere mich jetzt, warum ich das _end__ nicht hineingesteckt habe. weil es nicht funktioniert.

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

Ein einfacher, aber sehr portabler Code, um dieses Linker-Skript zu heiraten

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
bss_zero:
    stmia r1!,{r2}
    sub r0,#4
    bne bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3}
    stmia r2!,{r3}
    sub r0,#4
    bne data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__

geben

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000003d    andeq   r0, r0, sp, lsr r0
   c:   0000003d    andeq   r0, r0, sp, lsr r0
  10:   0000003d    andeq   r0, r0, sp, lsr r0

00000014 <reset>:
  14:   480c        ldr r0, [pc, #48]   ; (48 <blen>)
  16:   2800        cmp r0, #0
  18:   d004        beq.n   24 <bss_zero_done>
  1a:   490a        ldr r1, [pc, #40]   ; (44 <bstart>)
  1c:   2200        movs    r2, #0

0000001e <bss_zero>:
  1e:   c104        stmia   r1!, {r2}
  20:   3804        subs    r0, #4
  22:   d1fc        bne.n   1e <bss_zero>

00000024 <bss_zero_done>:
  24:   480b        ldr r0, [pc, #44]   ; (54 <dlen>)
  26:   2800        cmp r0, #0
  28:   d005        beq.n   36 <data_copy_done>
  2a:   4908        ldr r1, [pc, #32]   ; (4c <rstart>)
  2c:   4a08        ldr r2, [pc, #32]   ; (50 <dstart>)

0000002e <data_copy>:
  2e:   c908        ldmia   r1!, {r3}
  30:   c208        stmia   r2!, {r3}
  32:   3804        subs    r0, #4
  34:   d1fb        bne.n   2e <data_copy>

00000036 <data_copy_done>:
  36:   f000 f80f   bl  58 <centry>
  3a:   e7ff        b.n 3c <done>

0000003c <done>:
  3c:   e7fe        b.n 3c <done>

0000003e <bounce>:
  3e:   46c0        nop         ; (mov r8, r8)
  40:   4770        bx  lr
  42:   46c0        nop         ; (mov r8, r8)

00000044 <bstart>:
  44:   20000008    andcs   r0, r0, r8

00000048 <blen>:
  48:   00000004    andeq   r0, r0, r4

0000004c <rstart>:
  4c:   00000074    andeq   r0, r0, r4, ror r0

00000050 <dstart>:
  50:   20000000    andcs   r0, r0, r0

00000054 <dlen>:
  54:   00000008    andeq   r0, r0, r8

00000058 <centry>:
  58:   2207        movs    r2, #7
  5a:   b510        push    {r4, lr}
  5c:   4b04        ldr r3, [pc, #16]   ; (70 <centry+0x18>)
  5e:   2007        movs    r0, #7
  60:   601a        str r2, [r3, #0]
  62:   f7ff ffec   bl  3e <bounce>
  66:   2000        movs    r0, #0
  68:   bc10        pop {r4}
  6a:   bc02        pop {r1}
  6c:   4708        bx  r1
  6e:   46c0        nop         ; (mov r8, r8)
  70:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

wir können dort anhalten oder weitermachen. Wenn wir in der gleichen Reihenfolge wie das Linker-Skript initialisieren, ist es in Ordnung, wenn wir mit dem nächsten Schritt fortfahren, da wir dort noch nicht angekommen sind. und stm / ldm sind nur erforderlich / erwünscht, um wortausgerichtete Adressen zu verwenden. Wenn Sie also zu Folgendem wechseln:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

mit bss zuerst im linker script, und ja du willst ble nicht bls.

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3804        subs    r0, #4
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000004    andcs   r0, r0, r4

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

Diese Schleifen werden schneller gehen. Jetzt weiß ich nicht, ob die Ahb-Busse 64 Bit breit sein können oder nicht, aber für einen Arm voller Größe möchten Sie diese Dinge an 64-Bit-Grenzen ausrichten. Ein ldm / stm mit vier Registern an einer 32-Bit-Grenze, jedoch keine 64-Bit-Grenze, wird zu drei separaten Bustransaktionen, wobei an einer 64-Bit-Grenze eine einzelne Transaktion ausgerichtet ist, die mehrere Takte pro Befehl spart.

Da wir Baremetall machen und wir für alles verantwortlich sind, was wir sagen können, sagen wir zuerst bss, dann Daten. Wenn wir dann Heap haben, wächst der Stapel von oben nach unten. Wenn wir also bss auf Null setzen und etwas überlaufen, solange wir anfangen Am richtigen Ort, der in Ordnung ist, verwenden wir diesen Speicher noch nicht. Dann kopieren wir .data und können in den Heap gelangen, der in Ordnung ist, Heap oder nicht, es gibt viel Platz für den Stack, so dass wir auf niemanden / irgendetwas treten (solange wir im Linker-Skript sicherstellen, dass wir das tun. Wenn es Bedenken gibt, vergrößern Sie die ALIGN (), damit wir immer innerhalb unseres Bereichs für diese Füllungen sind.

Also meine einfache Lösung, nimm es oder lass es. Willkommen, um Fehler zu beheben, ich habe dies weder auf Hardware noch auf meinem Simulator ausgeführt ...

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(8);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

   . = ALIGN(8);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

}



.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3,r4,r5,r6}
    stmia r2!,{r3,r4,r5,r6}
    sub r0,#16
    ble data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__


void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

arm-none-eabi-as --warn --fatal-warnings flash.s -o flash.o
arm-none-eabi-ld -o hello.elf -T flash.ld flash.o centry.o
arm-none-eabi-objdump -D hello.elf > hello.list
arm-none-eabi-objcopy hello.elf hello.bin -O binary

Füge alles zusammen und du bekommst:

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3810        subs    r0, #16
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000008    andcs   r0, r0, r8

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

Beachten Sie, dass dies mit arm-none-eabi- und arm-linux-gnueabi und den anderen Varianten funktioniert, da kein Ghee-Whiz-Material verwendet wurde.

Sie werden feststellen, wenn Sie sich umschauen, dass die Leute verrückt nach Ghee Whiz-Sachen in ihren Linker-Skripten werden, riesigen monströsen Küchenspülen. Es ist besser, nur zu wissen, wie es geht (oder besser, wie man die Werkzeuge beherrscht, damit Sie steuern können, was vor sich geht), als sich auf andere Dinge zu verlassen und nicht zu wissen, wo es kaputt gehen wird, weil Sie nicht verstehen und / oder recherchieren wollen es.

In der Regel wird keine Sprache mit derselben Sprache gebootet (Bootstrap bedeutet in diesem Sinne, dass Code ausgeführt wird, der keinen Compiler mit demselben Compiler kompiliert). Sie möchten eine einfachere Sprache mit weniger Bootstrap verwenden. Aus diesem Grund wird C in der Assembly ausgeführt. Es gibt keine Bootstrap-Anforderungen, die Sie erst nach dem Zurücksetzen mit der ersten Anweisung beginnen. JAVA, sicher, dass Sie die JVM in C schreiben und das C mit asm booten und dann die JAVA booten, wenn Sie mit C wollen, aber auch die JAVA in C ausführen.

Da wir die Annahmen für diese Kopierschleifen kontrollieren, sind sie per Definition enger und sauberer als handgestimmte Memcpy / Memsets.

Beachten Sie, dass Ihr anderes Problem folgendes war:

unsigned int * bss_start_p = &_BSS_START; 
unsigned int * bss_end_p = &_BSS_END;

Wenn diese lokal in Ordnung sind, kein Problem. Wenn diese global sind, müssen Sie zuerst .data initialisieren, damit sie funktionieren. Wenn Sie diesen Trick versuchen, um .data auszuführen, schlagen Sie fehl. Lokale Variablen, gut, das wird funktionieren. Wenn Sie sich aus irgendeinem Grund entschlossen haben, die statischen Einheimischen (lokale Globale, die ich gerne nenne) zu machen, sind Sie wieder in Schwierigkeiten. Jedes Mal, wenn Sie eine Aufgabe in einer Erklärung ausführen, sollten Sie darüber nachdenken, wie diese implementiert wird und ob sie sicher / vernünftig ist. Jedes Mal, wenn Sie davon ausgehen, dass eine Variable bei Nichtdeklaration Null ist, gilt dies auch dann, wenn eine lokale Variable nicht als Null angenommen wird, wenn sie global ist. Wenn Sie nie davon ausgehen, dass sie Null sind, müssen Sie sich keine Sorgen machen.

Oldtimer
quelle
genial, dies ist das zweite Mal, dass ich die maximale Anzahl von Zeichen in einer Antwort überschritten habe ....
old_timer
Diese Frage gehört zum Stackoverflow nicht zur Elektrotechnik.
old_timer
Auch das Verlassen auf einen externen Link in Ihrer Frage ist keine gute Form. Wenn der Link vor der Frage verschwindet, ist die Frage möglicherweise nicht sinnvoll.
old_timer
In diesem Fall reicht Ihr Titel und Inhalt aus, um zu wissen, dass Sie versuchen, C auf einem bestimmten Mikrocontroller zu booten, und in die Initialisierung von .bss und .data wechseln
old_timer
aber in diesem Fall wurden durch eine ansonsten sehr informative Website irregeführt.
old_timer