Forum: Mikrocontroller und Digitale Elektronik Position Independent Code generieren?


von Tobias P. (hubertus)


Lesenswert?

Hallo,

ich habe folgendes Problem. Ich setze hier einen MPC555 PowerPC ein. An 
diesem sind 8MB Flash extern angebunden, sowie 1MB RAM. Die Applikation, 
die ausgeführt werden soll, wird beim Booten teilweise ins RAM kopiert, 
da dort die Ausführung schneller ist (z.B. irgendwelche digitalen Regler 
usw.). Der TCP-Stack hingegen und ein paar andere Teile, die nicht so 
kritisch sind, laufen aus diesem externen Flash. Ich soll jetzt eine 
Software implementieren, die das Laden einer neuen Software via Browser 
& TCP/IP ermöglicht. Das klappt auch ganz gut; in der Applikation ist 
ein kleiner Webserver integriert, der mittels HTML-Formular eine Datei 
hochladen und im Flash speichern kann. Nun habe ich mir zum Updaten der 
Software folgendes ausgedacht.
Man teilt den Flash-Speicher in zwei Teile (Applikation ist < 4MB gross, 
passt also) und überschreibt beim Softwareupdate dann die jeweils ältere 
Version. Ein kleiner Bootloader, der im internen Flash des PowerPC 
sitzt, schaut beim Booten dann nach, welche Version neuer ist, und 
startet dementsprechend diese.
Das Problem an der ganzen Sache ist jetzt aber: diejenigen Codeteile, 
die aus dem Flash ausgeführt werden, müssen Position-independent sein, 
da ich zur Compilierzeit ja nicht weiss, von wo aus mein Code ausgeführt 
wird.
Diejenigen Teile hingegen, die aus dem RAM laufen, sollen so bleiben, 
wie sie sind.
Die Frage, die sich mir jetzt natürlich stellt: Ist so ein Setup 
grundsätzlich überhaupt möglich? Kann ich Teile der Applikation so 
kompilieren lassen, dass ich sie irgendwo ins Flash speichern kann, und 
die Ausführung dann trotzdem klappt? Zumindest die Hardwareregister und 
das externe RAM müssen ja dann doch wieder absolut adressiert werden.

Und falls einer den Diab PowerPC Compiler kennt und mir ein wenig 
Hilfestellung geben könnte, wär das auch toll ;-)
von Alexxx (Gast)


Lesenswert?

Hallo,

da es sich um Programmierung handelt bist du eigentlich im falschen 
Forum!?
von Tobias P. (hubertus)


Lesenswert?

Danke für deinen nicht sehr hilfreichen Beitrag.

1. handelt es sich um Mikrocontroller & Elektronik. Passt also.
2. Da ich nicht den GCC verwende, gehört es nicht ins GCC Forum.
3. Kein Fertiger Code, keine PC-Software, mit Ausbildung, Offtopic, HF & 
Funk & Feldern usw. hat es auch nichts zu tun, erst recht mache ich 
keine Leiterplatte, also gehört der Thread da auch nicht rein.
von Jim M. (turboj)


Lesenswert?

Wieso lässt Du Deinen Bootloader nicht einfach den "hinteren" Teil des 
Flash Speichers auf den "vorderen" kopieren?
von Oliver (Gast)


Lesenswert?

Tobias Plüss schrieb:
> Die Frage, die sich mir jetzt natürlich stellt: Ist so ein Setup
> grundsätzlich überhaupt möglich?

Antorten zu möglichen Memory-Modellen und "positionsunabhängigem" Code 
sollten eigentlich in der Dokumentation zu deinem Compiler bzw. 
Entwicklungssystem zu finden sein.

Oliver
von Tobias P. (hubertus)


Lesenswert?

Jim Meba,
das Kopieren wollte ich wenn möglich vermeiden. Wenn jemand in dem 
Moment, wo kopiert wird, den Netzstecker zieht, oder sonst was schief 
geht, dann ist die zuvor lauffähige Applikation zerschossen und der 
Benutzer hat ein Problem. Mit dem PIC-Code hätte ich immer noch als 
"Backup" die jeweils ältere Version der Software bereits im Memory.

Oliver,
ja natürlich, ich habe das Compilermanual gelesen. Aber leider hat der 
dort angegebene Compilerswitch nicht funktioniert; der Compiler bringt 
Fehlermeldungen. Dazu gibts wohl 2 Gründe:

1. Woher soll der Compiler wissen, dass gewisse Teile der Applikation 
zur Ausführung ins RAM kopiert werden und somit an einer festen Adresse 
liegen, im Gegensatz zum Flash-Code, der irgendwo liegen kann?

2. Der Compiler kann scheinbar Sprungtabellen, die irgendwelche 
Funktionspointer enthalten, nicht Position Independent compilieren. Aber 
das kann doch nicht sein? Wozu soll eine PIC-Option da sein, wenn sie 
keine Funktionspointer compilieren kann? Ich blicke da nicht so ganz 
durch.

Leider ist unser Compiler hier von 1999, und der Support schon längst 
abgelaufen. Sonst hätte ich da längst ne Mail hin geschickt ;-)
von Εrnst B. (ernst)


Lesenswert?

Tobias Plüss schrieb:
> 2. Der Compiler kann scheinbar Sprungtabellen, die irgendwelche
> Funktionspointer enthalten, nicht Position Independent compilieren. Aber
> das kann doch nicht sein? Wozu soll eine PIC-Option da sein, wenn sie
> keine Funktionspointer compilieren kann? Ich blicke da nicht so ganz
> durch.

Logisch dass das nicht geht.
Normalerweise (!PIC) würde der Linker schon zur Compile-Time die 
Funktionstabellen (mit Konstanten) füllen. Bei PIC-Code stehen diese 
aber noch nicht fest.

d.H. beim Laden/verschieben des Codes müssten alle Funktionspointer 
verändert werden. Kein Problem, dafür gibts "dynamische Linker".

http://en.wikipedia.org/wiki/Dynamic_linker
http://en.wikipedia.org/wiki/Dynamic_loading

Diese gibts natürlich auch für PowerPC, aber halt üblich im 
Betriebsystem-Kontext. (linux, ld.so, elf-dateien)
von Tobias P. (hubertus)


Lesenswert?

Naja, so logisch finde ich das jetzt nicht :-)
Wenn ich in den Funktionstabellen anstatt der absoluten Adresse jeder 
Funktion nur deren Offset speichere, dann ist doch alles in Ordnung. 
Dann muss ich zur Startadresse meines Programms nur noch diesen Offset 
dazu addieren, dann ist mir jede Funktion bekannt.

Es gab meines Wissens für 68k Prozessoren mal ein Betriebssystem, wo 
sämtlicher Code vollständig position independent war und alles von einer 
nahezu beliebigen Adresse her ausgeführt werden konnte. Leider weiss ich 
nicht genau, wie das gemacht wurde.

Ein ELF-Loader wird hier nicht funktionieren, da das ELF-File ja 
ungünstigerweise im Flash liegt und nur bestimmte Teile aus dem RAM 
laufen, während andere Teile weiter im Flash bleiben sollen :-/
von Εrnst B. (ernst)


Lesenswert?

Tobias Plüss schrieb:
> ungünstigerweise im Flash liegt und nur bestimmte Teile aus dem RAM
> laufen, während andere Teile weiter im Flash bleiben sollen :-/

Damit beschreibst du genau, warum deine Idee (Relative statt Absolute 
Funktionspointer) nicht funktioniert.
Weil: Du brauchst ja beide Arten (absolute Pointer in den Flash, 
relative für PIC code)
Welcher Typ wo gebraucht wird, kann der Compiler nicht wissen, da 
Funktionspointer evtl. erst zur Laufzeit gesetzt und geändert werden.
Also muss der Programmierer ran, und das dem Compiler mitteilen.
Leider bietet C nur einen Pointer-Typ an, d.H. mit Plain-C geht das 
nicht.

Also: Assembler muss ran. Damit geht auch sowas:

Tobias Plüss schrieb:
> Es gab meines Wissens für 68k Prozessoren mal ein Betriebssystem, wo
> sämtlicher Code vollständig position independent war


Mit viel Fleiß lasst sich ein relativer Funktions-Pointer vielleicht 
als C++-Template-Klasse mit inline-ASM machen, aber auch da habe ich 
meine Zweifel.

Überleg mal, welchen Aufwand alleine die Umsetzung dieses 
Pseudo-Code-Schnippsels machen würde:
1
  relative_function_ptr_t a;
2
  relative_function_ptr_t b;
3
4
  // Bedenke, a enthält den Offset zwischen der Funktion und der eigenen Speicherstelle, der muss berechnet werden.
5
  a=calculate_function_offset_relative(fun_a, &a);
6
7
  // Bedenke: b liegt an einer anderen Speicherstelle als a, die Zuweisung muss den Wert verändern!
8
  // d.H. diese Zuweisung muss anderen Code ausführen als die obere.
9
  b=a;
von (prx) A. K. (prx)


Lesenswert?

Ich habe aus einem früheren Jahrhundert vage in Erinnerung, dass AIX 
Adresstabellen verwendet, d.h. ein Register zeigt stets auf die 
Adresstabelle des aktuellen Moduls. Weil die PowerPCs in den Befehlen 
weder den ganzen Adressraum erfassen, noch wie ARMs auf einfache Art 
relativ zum Program Counter adressieren können (ausser in 
Sprungbefehlen).

Auf dem Weg lässt sich positionsunabhängiger Code erzeugen, indem diese 
Adresstabellen nicht fester Bestandteil vom Program-Image sind, sondern 
vom Loader erzeugt werden. Das kommt sicherlich auch den (nicht nur) in 
Unix recht verbreiteten shared libraries entgegen.
von Tobias P. (hubertus)


Lesenswert?

Hmm,
okay, dann geht das dann wohl doch nicht, so wie ich mir das vorstelle?
Ich bin grade noch am Überlegen, ob ich eventuell mit dem Memory 
Controller des MPC555 gewisse Bereiche vom Flash ummappen kann. Konkret 
stelle ich mir das so vor:

Das Flash beginnt ab Adresse 0x2000000. Die Applikation wird auch für 
diese Adresse kompiliert (kein PIC-Code). Wenn ich eine neue Software 
runter lade, dann wird diese an Adresse 0x2400000 gespeichert. Und nun 
"verbiege" ich mit dem Memory Controller den Adressbereich des Flash so, 
dass die Adresse 0x2400000 und 0x2000000 "getauscht" werden. Geht sowas 
wohl? Kennt hier jemand diesen Prozessor?
Ich muss zugeben, dass ich von der MPC555 Hardware nicht sehr viel 
Ahnung habe. Es ist ein schrecklicher Prozessor und ich befasse mich 
möglichst nicht mit Hardwareabhängigkeiten, aber jetzt komme ich wohl 
nicht drum herum ;-)
von (prx) A. K. (prx)


Lesenswert?

Du wirst vor allem nicht darum herumkommen, überhaupt erst einmal 
festzustellen, wie der Compiler mit Adressen umgeht. Wenn er sie als 
Literals in 2 Befehlen zusammen baut hast du verloren. Wenn er Tabellen 
verwendet, stehen die Chancen besser.
von Tobias P. (hubertus)


Lesenswert?

A.K.,
ja das mit dem PIC und PID propagieren sie, dass der Compiler das kann.
Wenn ich compiliere, kommt aber Fehler Nr. 1061: "Address taken in 
initializer". Im Handbuch steht zu diesem Fehler: "You used the Address 
of a Variable or Function in a variable's initializer. For such code, 
PIC/PID does not work."
Meines erachtens sollte man das aber können, wenn ich keine Pointer 
benutzen kann, dann ist es ja sinnfrei, eine PIC-option überhaupt 
anzubieten :o
von (prx) A. K. (prx)


Lesenswert?

Tobias Plüss schrieb:

> "Address taken in initializer".

Nun kommen wir der Sache schon näher. Du kannst durchaus Pointer 
verwenden, aber nicht als statisch initialisierte Variablen. Was also 
nicht geht:
   static int x;
   static int *px = &x;
oder analog mit Zeigern auf Funktionen. Das Problem dürfte verschwinden, 
wenn diese Variablen zur Laufzeit initialisiert werden.
von Joerg W. (joergwolfram)


Lesenswert?

Eventuell ist es einfacher, den Code für die beiden möglichen Positionen 
zu übersetzen und in ein File zusammenzupacken. Der Bootloader 
entscheidet dann, welchen Teil er zum Flashen verwendet und ignoriert 
den Rest.

Jörg
von Tobias P. (hubertus)


Lesenswert?

Naja, ich sehe das Problem nicht. Dieser Code wird dann ja eh ins RAM 
kopiert und läuft von einer festen Adresse aus :-) Wirklich nur der 
Code, der die Applikation ins RAM kopiert sowie der TCP/IP Stack und das 
User Interface müssen Position Independent sein, denn nur diese werden 
aus dem Flash, und somit von unterschiedlichen Adressen aus, ausgeführt. 
Leider bietet der Compiler keine Option an, um nur einzelne Dateien 
Position Independent zu compilieren; entweder kann ich nur das ganze 
Projekt oder nichts, jedenfalls so wie ich das jetzt verstehe.
Lustigerweise unterstützt der Compiler aber Features wie vorhergehendes 
ins-RAM-Kopieren von Code und implementiert das richtig. :-/
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.