Forum: Compiler & IDEs PROGMEM Adresse in uint8_t-Array speichern


von Mirko K. (mka)


Lesenswert?

Hallo,

ich habe mehrere uint8_t-Arrays im PROGMEM, die eine Art Bytecode für 
eine Ablaufsteuerung enthalten. Nun möchte innerhalb eines solchen 
Arrays den Pointer auf ein anderes Array ablegen. Wegen des uint8_t muss 
ich den noch in High- und Low-Byte zerlegen:

#include <inttypes.h>
#include <avr/pgmspace.h>

uint8_t PROGMEM prog_thread1[] = { 1, 2, 3 };

uint8_t PROGMEM prog_main[] = {
  42, // ... beliebig viele weitere Bytes
  (uint8_t)(((uint16_t)prog_thread1) &  0xff),
  (uint8_t)(((uint16_t)prog_thread1) >> 8),
};

avr-gcc -c -mmcu=atmega16   foo.c
foo.c:7: error: initializer element is not constant
foo.c:7: error: (near initialization for 'prog_main[0]')
foo.c:8: error: initializer element is not constant
foo.c:8: error: (near initialization for 'prog_main[1]')

Was ist denn an dem prog_thread1 Pointer nicht konstant? Hat jemand eine 
Idee für einen Workaround mit dem avr-gcc (Version 4.2.2) oder weiß wie 
man das richtig macht?

von Mirko K. (mka)


Lesenswert?

Ich glaube ich komme langsam dahinter was hier passiert. Vielleicht kann 
mir jemand meine Vermutung bestätigen:
Für den Compiler ist die Adresse von prog_thread1 zwar konstant, aber 
nur innerhalb des Object-Files bekannt. Die Adresse schreibt er in die 
Symboltabelle. Die wirkliche Adresse setzt aber am Ende der Linker ein 
und der muss sie u.a. aus dem Eintrag der Symboltabelle berechnen.
Die logischen Verknüpfungen zur Trennung in Hi und Lo Byte (& und >>) 
müssen auf die vom Linker berechnete Adresse angewendet werden. Der 
Compiler kann das noch nicht machen. Der Linker ist für sowas 
(verständlicherweise) nicht ausgelegt.

Wenn ich das Array, in das ich die Adresse einfügen will, zu einem 
uint16_t mache, entfallen die & und >> Operationen und es funktioniert 
(danke Jörg):

uint8_t  prog_thread1[] = { 1, 2, 3 };
uint16_t  prog_main[] = {
  42,
  (uint16_t)prog_thread1
};

Das möchte ich allerdings vermeiden, da ich so meinen Kommandosatz auf 
16 Bit umstellen muss und wegen einer Reihe von 3 Byte Befehlen 
reichlich Verschnitt hätte.
Hat jemand eine Idee, wie man das mit 8 Bit Arrays hinbekommen kann?

Mirko

von Klaus W. (mfgkw)


Lesenswert?

Notfalls halt nicht als Initialisierung, sondern gleich nach
Programmstart mit einer normalen Zuweisung?

von Mirko K. (mka)


Lesenswert?

Die Arrays sind im Flash. Das PROGMEM hatte ich im ersten Beitrag noch 
drin, im zweiten dann aber vergessen.

von Grrrr (Gast)


Lesenswert?

Vielleicht wäre es auch ein Weg, in prog_main nicht Adressen sondern 
Indizes zu speichern?

von Mirko K. (mka)


Lesenswert?

Ja, die Idee hatte ich auch schon. So in der Art:

#include <inttypes.h>
#include <avr/pgmspace.h>

uint8_t  prog_thread1[] = { 1, 2, 3 };

prog_uint8_t *thread_addresses[] = {
  prog_thread1
  /* , weitere Adressen */
};

uint8_t  prog_main[] = {
  42,
  0 /* Index ins thread_addresses[] Array */
};

Mein Programm muss dann über thread_addresses[i] die Adresse holen. Es 
ist zwar nicht so schön, das thread_addresses-Array noch extra pflegen 
zu
müssen, erscheint mir aber noch praktikabel. Ich glaube so werde ich es 
machen.

Danke, wieder was gelernt :-)

Mirko

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Mirko Kaffka schrieb:

> Die logischen Verknüpfungen zur Trennung in Hi und Lo Byte (& und >>)
> müssen auf die vom Linker berechnete Adresse angewendet werden. Der
> Compiler kann das noch nicht machen. Der Linker ist für sowas
> (verständlicherweise) nicht ausgelegt.

Ja, ich denke auch, dass das das Problem ist.

Der Linker von RSX-11 (dort "taskbuilder" genannt) auf der PDP-11
konnte sowas. ;-)  Die haben im Objektcode einen RPN-Faden mit
Berechnungen ablegen können, die auf das Symbol anzuwenden sind bei
der Relokation.  Ich hatte dafür mal einen Disassembler geschrieben
und hatte die Ehre, aus dem RPN-Faden eine algebraische Darstellung
zu erfinden. :)

Der Unix-Linker kann das nicht.  Alles, was der machen soll, muss als
"relocation record type" zwischen Assembler und Linker vereinbart
worden sein.  In diesem Falle hier bedürfte es offenbar sogar noch
einer Vereinbarung zwischen Compiler und Assembler, wie man sowas
auf Assembler-Niveau ausdrücken soll.

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.