Forum: Compiler & IDEs Startadresse für .data bei Harvard-Architektur


von VHDL hotline (Gast)


Lesenswert?

Hallo,

ich habe eine Verständnis- bzw. Implementierungsfrage zum Adressraum 
eines gcc-Programms. Als uC nutze ich einen OpenRISC in einem FPGA, 
allerdings sollte die Frage erstmal unabhängig vom target sein.

So wie ich es verstehe, steht grob gesagt im Adressraum (von Adresse 0 
bis max) .text .data .bss .heap .stack.

Das was in .text steht ist mein Befehlsspeicher. Das was im Rest steht, 
sind Daten, richtig?

Wenn ich nun einen Prozessor mit Harvard-Architektur habe (z.B. 
bestimmte OpenRISC Implementierungen), d.h. getrennte Busse für Befehle 
und Daten, wird meines Verständnisses nach alles in der .text über den 
Befehlsbus adressiert und alles andere über den Datenbus.

Was ich gern (im FPGA) bauen möchte, sind zwei getrennte Speicher für 
Befehle und Daten. Der Befehlsspeicher soll eine fixe Größe von z.B 
16KByte haben, d.h. .text ist 16Kbyte groß.

Kann ich einfach während des Bauens dem gcc die Option
1
-Wl,--section-start=.data=0x00004000
mitgeben, um einen (read only) Befehlsspeicher von 0x00000000 bis 
0x00003FFF und einen Datenspeicher von 0x00004000 bis max zu haben (d.h. 
.text, .bss .heap .stack landet ab 0x00004000 im Datenspeicher)? Kann 
ich dann einfach die per objdump nach out.bin gewandelte out.elf als 
Initialbelegung in den Befehlsspeicher schreiben?

Oder ist das zu einfach gedacht?

Wenn ich einen gcc-size auf die erstellte out.elf mache, gibt es ja 
Größen für .text, .data und .bss. Liegen in der .elf irgendwelche 
.data/.bss Sachen, die doch schon (zur Bauzeit des FPGA mittels 
Initialisierung) in den Datenspeicher müssen oder werden .data und .bss 
mittels startup-code zur Laufzeit geschrieben und der Speicherbereich 
für .data und .bss muss nur leer im Datenspeicher verfügbar sein?

Danke für jede Hilfe.
Vh

von Bernd K. (prof7bit)


Lesenswert?

VHDL hotline schrieb im Beitrag #4095340:
> Kann ich einfach während des Bauens dem gcc die
> Option-Wl,--section-start=.data=0x00004000
> mitgeben, um einen (read only) Befehlsspeicher von 0x00000000 bis
> 0x00003FFF und einen Datenspeicher von 0x00004000 bis max zu haben (d.h.
> .text, .bss .heap .stack landet ab 0x00004000 im Datenspeicher)?

Müsste gehen. Als Option an der Kommandozeile hab ichs noch nicht 
probiert, aber wenn Du ein Linkerscript hast und dort die Startadressen 
entsprechend definierst dann geht das so auf jeden Fall. An der 
Kommandozeile wahrscheinlich auch, warum auch nicht?

> Kann
> ich dann einfach die per objdump nach out.bin gewandelte out.elf als
> Initialbelegung in den Befehlsspeicher schreiben?

Ja.

von Bernd K. (prof7bit)


Lesenswert?

VHDL hotline schrieb im Beitrag #4095340:
> Liegen in der .elf irgendwelche
> .data/.bss Sachen,

.data sollte ans Ende des .text kommen, da liegen die Werte mit denen 
globale Variablen initialisiert werden (macht der Starup-code [den Du 
schreibst], der soll das dann vom Programmspeicher (von der Stelle an 
der .data anfängt) in den Datenspeicher (an die Stelle an der .bss 
anfängt) kopieren. Das wird alles im Linkerscript so definiert (z.B. daß 
.data am ende von .text kommen soll und alles zusammen dann in den 
Programmspeicher verfrachtet werden soll), wie man ihm das allerdings 
über eine  Kommandozeilenoption beibringt (wenn er es nicht schon von 
sich aus macht und kein Linkerscript da ist) weiß ich allerdings nicht.

.bss landet im RAM (steht auch im Linkerscript)

: Bearbeitet durch User
von asdfasd (Gast)


Lesenswert?

Bei einer Harvard-Architektur spricht nichts dagegen, sowohl Code als 
auch Daten bei 0 beginnen zu lassen (ist bei all den mir bekannten 
Harvard-CPUs der Fall).  In welcher Reihenfolge und an welchen Offsets 
Code und Daten in einem bin- bzw. hex-File liegen, hat damit überhaupt 
nichts zu tun.

von DJ T. (Gast)


Lesenswert?

VHDL hotline schrieb im Beitrag #4095340:
> Wenn ich einen gcc-size auf die erstellte out.elf mache, gibt es ja
> Größen für .text, .data und .bss. Liegen in der .elf irgendwelche
> .data/.bss Sachen, die doch schon (zur Bauzeit des FPGA mittels
> Initialisierung) in den Datenspeicher müssen oder werden .data und .bss
> mittels startup-code zur Laufzeit geschrieben und der Speicherbereich
> für .data und .bss muss nur leer im Datenspeicher verfügbar sein?

Wenn Du Dein System einschaltest, ist das RAM ja erstmal undefiniert, 
d.h. die Sections .data und .bss (beide liegen im Datenspeicher/RAM) 
enthalten erstmal Müll.
Jetzt läuft Dein Program aus dem Codespeicher los und der Startup-Code 
(den der GCC heimlich für Dich eingebaut hat) initialisiert den 
Datenspeicher (RAM). Dabei gilt:
Die Section .bss wird einfach komplett mit 0 beschrieben.
In die Section .data werden die Initialwerte der initialisierten 
Variablen kopiert, die in der Section .text hinterlegt sind.

Alle Informationen, die Dein Programm zum Laufen benötigt, liegen also 
allein in der .text Section, während sich .bss und .data quasi aus den 
im .text hinterlegten Adressen und dem Startup-Code ergeben.

von VHDL hotline (Gast)


Lesenswert?

Danke erstmal für alle Antworten.

Bernd K. schrieb:
> .data sollte ans Ende des .text kommen, da liegen die Werte mit denen
> globale Variablen initialisiert werden (macht der Starup-code [den Du
> schreibst], der soll das dann vom Programmspeicher (von der Stelle an
> der .data anfängt) in den Datenspeicher (an die Stelle an der .bss
> anfängt) kopieren. Das wird alles im Linkerscript so definiert

Also liegen nur die Werte für .data schon im .elf file (in der .text 
section) oder .data selbst?

Laut

DJ Tobsen schrieb:
> Wenn Du Dein System einschaltest, ist das RAM ja erstmal undefiniert,
> d.h. die Sections .data und .bss (beide liegen im Datenspeicher/RAM)

wohl ersteres? Mache ich aber einen objdump auf mein elf-file, sehe ich 
im dump ein .data mit den globalen Variablen.

Mein Problem ist, dass ich im FPGA ja selbst Befehls- und Datenspeicher 
instanziiere, die jeweils bei Adresse 0 anfangen, so wie hier schon 
angemerkt

asdfasd schrieb:
> Bei einer Harvard-Architektur spricht nichts dagegen, sowohl Code als
> auch Daten bei 0 beginnen zu lassen

Die Speicher verbinde ich mit den entsprechenden Bussen und muss diese 
natürlich selbst irgendwie laden.
Mein Plan ist, dass ich den Befehlsspeicher mit dem lade, was im .elf 
file steht (objcopy binary in den Speicher laden), der Datenspeicher 
bleibt erstmal leer (und wird zur Laufzeit initialisiert). .data muss 
dann aber wirklich komplett im Datenspeicher (und damit nicht in der 
elf-Datei initialisiert) liegen, da der Datenbus nur dort Zugriff hat.

von Steffen R. (steffen_rose)


Lesenswert?

Das Linkerscript sollte genaues wissen.

von Steffen R. (steffen_rose)


Lesenswert?

VHDL hotline schrieb im Beitrag #4101386:
> Mein Plan ist, dass ich den Befehlsspeicher mit dem lade, was im .elf
> file steht (objcopy binary in den Speicher laden), der Datenspeicher
> bleibt erstmal leer (und wird zur Laufzeit initialisiert). .data muss
> dann aber wirklich komplett im Datenspeicher (und damit nicht in der
> elf-Datei initialisiert) liegen, da der Datenbus nur dort Zugriff hat.

Das ist üblich so.
Bedeutet natürlich, dass es auch Befehle geben muß, die Daten vom 
Befehlsspeicher lesen können. Manchmal werden diese dann auch zur 
Implementierung von .const genutzt.

von Bernd K. (prof7bit)


Lesenswert?

VHDL hotline schrieb im Beitrag #4101386:
> Also liegen nur die Werte für .data schon im .elf file (in der .text
> section) oder .data selbst?

Genau so wie ichs gesagt habe: Die liegen in .data (und das liegt im 
flash, zusammen mit dem .text aber als eigene Sektion, .data eben) und 
alles in .data wird zur Laufzeit im startup an die richtige Stelle im 
Arbeitsspeicher kopiert. Und wo genau diese Stellen sind wird im 
Linkerscript definiert, dort werden auch Symbole definiert auf die sich 
später der Startup code beziehen kann damit er genau weiß was er von 
welcher Adresse nach wo genau (und wieviel) kopieren soll.

Schau einfach mal wie es sich bei einen AVR (das ist Harward) verhält, 
mach zu Anschauungszwecken ein kleines Testprogramm mit ein paar 
globalen Variablen, ein paar davon initialisierst Du mit 0, ein paar 
davon mit was anderem (irgendwas was leicht im Hex-Editor wiederzufinden 
ist), dann schaust Du Dir die sections im .elf an, was wo drin ist, 
anschließend schaust Du Dir das .bin oder das .hex an und vergleichst 
welche Sections Du da wiederfindest und welche nicht und dann schaust Du 
Dir noch an was der startup code unmittelbar nach dem Reset alles macht, 
was er wie initialisiert und woher er die Daten dafür nimmt.

Wenn Du kein .data haben willst dann sorge dafür daß es Größe 0 hat 
indem Du keine statischen globalen Initializer verwendest, dann entfällt 
auch das Problem Daten vom Programmspeicher in den Arbeitsspeicher 
kopieren zu müssen. Dann musst Du Dich nur noch um .text kümmern, Dein 
.bin file wird dann auch nur noch .text und sonst nichts mehr enthalten, 
das lädst Du in Deinen Programmspeicher und startest es, den Rest macht 
dann Dein Programm.

: Bearbeitet durch User
von Bronco (Gast)


Lesenswert?

VHDL hotline schrieb im Beitrag #4101386:
> Also liegen nur die Werte für .data schon im .elf file (in der .text
> section) oder .data selbst?

Stell Dir mal vor, Du hast ein ELF-File für einen PC mit Betriebssystem.
Das ELF-File enthält .text + .data + .bss.
Beim Laden des ELF-Files (zur Laufzeit) macht der Fileloader des 
Betriebssystem nun folgendes:
Er reserviert soviel RAM, wie .text benötigt und lädt .text dort hin.
Er reserviert soviel RAM, wie .data benötigt und lädt .data dort hin.
Er reserviert soviel RAM, wie .bss benötigt und initialisiert dieses mit 
0.
=> Der Sinn, zwischen .data und .bss zu unterscheiden ist der, dass der 
.bss-Bereich nicht in der Datei gespeichert werden muß. Dadurch wird die 
Datei kleiner, was zu früheren Zeiten mal ein echter Vorteil war.

Stell Dir mal vor, Du hast ein ELF-File für einen µC ohne 
Betriebssystem.
Das ELF-File enthält .text + .data + .bss.
Es gibt aber kein Betriebssystem und auch keinen Fileloader, der das 
ELF-File zur Laufzeit lädt. Stattdessen muß der Debugger/Programmer aus 
dem ELF-File den Maschinencode herausziehen und ins Flash programmieren.
Der Maschinencode muß aber noch eine Extrafunktion enthalten, die beim 
Starten des Programmes die zur .data gehörigen Daten im RAM mit ihren 
Startwerten initialisiert und die zum .bss gehörigen Daten im RAM mit 0 
initialisiert. Diese Funktion steckt im Startup-Code.


Wichtig dabei:
Was im ELF-File steht landet nicht 1:1 im Flash!
Im ELF-File stecken viel mehr Informationen, z.B. die Namen Deiner 
Variablen, damit Du beim Debuggen bequem mit Variablennamen arbeiten 
kannst. Im Maschinencode hingegen stecken nur noch Adressen, aber keine 
symbolischen Namen mehr.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.