Forum: Compiler & IDEs Vorcompilierte lib per linker in speziellen Adressbereich mit festen Adressen möglich?


von hjdasjhskjhdkjashfkja (Gast)


Lesenswert?

hi
Ich habe eine vorcompilierte lib die recht groß ist.

Ist es möglich diese lib in einen definierten FLASH Bereich abzulegen
UND
dabei die Funktionen an bestestimmte Adressen zu legen?

Ziel soll sein das man nicht immer die komplette SW neu aufspielen muss 
.. sondern nur die eigentliche Anwendung.

Funktionen in einen bereich ablegen ist soweit kein thema.
NUR wird das jedesmal neu compiliert.

Mir entzieht sich momentan die kenntnis wie man die
Adressen exportieren kann..
Ebenso bräuchte ich da dann für die finale SW einen tabelle an welcher 
adresse welche funktion liegt ... richtig?

Idee beim schreiben :
1: die lib in einen FLASH block legen + compilieren ( wie am besten )
2: man exportiert die adressen aus der compilierten lib ( mapfile )
3: ein headerfile was funktionen auf die adressen mappt

dieses headerfile muss immer für diese lib/projekt genutzt werden

von hjdasjhskjhdkjashfkja (Gast)


Lesenswert?

vergessen:

Plattform ist Cortex M + GCC

von Jim M. (turboj)


Lesenswert?

Schau Dir mal den Source Code der CCC R0ket an:

https://github.com/r0ket/r0ket

Deren Firmware macht genau das: Eine feste "Symbol" Tabelle mit 
Einsprung Punkten direkt nach den Interrupt Vektoren.

Ein anderes Beispiel wäre das "Softdevice" für NordicSemi Bluetooth Low 
Energy Chips, die benutzen SVC Instruktionen.

von pegel (Gast)


Lesenswert?

Ich habe das mal für den "inoffiziellen" oberen 64k Bereich eines 
BluePill gemacht.

Im linker script habe ich ein "UPPER64K" Memory angelegt und in dessen 
section die Funktionen aufgelistet.

Die Funktionen lassen sich dann in einer Header Datei mit "extern" 
aufrufen.

von hjdasjhskjhdkjashfkja (Gast)


Lesenswert?

hi

Danke , schau ich mir an.

von Sid Greybeard (Gast)


Lesenswert?

Natürlich!
Das ging schon vor Urzeiten ('70er) als die 8-bit Welt noch rund war; 
Stichwort (E)PROMs.
Es gibt keinen Grund dass die 32-bit Welt flach sein muss.

von Bauform B. (bauformb)


Lesenswert?

Für maximale Geschwindigkeit bei minimalem Flash-Bedarf: Beim Linken der 
lib erzeuge ich ein Mapfile und kopiere die Adressen der Funktionen in 
eine Assembler-Quelle. Diese Datei wird zusammen mit meinem 
Hauptprogramm übersetzt und gelinkt. Das Programm benutzt ansonsten ganz 
normale C-Header für die Funktionen der lib und beim Linken wären die 
Adressen der Funktionen zunächst undefined.

Man darf nur nicht vergessen, nach einer Änderung der lib das 
Hauptprogramm auch neu zu linken. Das geht, weil die lib nur selten neu 
übersetzt wird, ansonsten braucht es eine "Symboltabelle" im Flash. Ein 
reine lib sollte kein SVC benutzen, wie würde das mit einem RTOS o.ä. 
zusammen spielen?

von hjdasjhskjhdkjashfkja (Gast)


Lesenswert?

hi

Danke nochmal für den schubser

Hatte gestern schon die lib an einer fixen stelle im Flash.
Leider klappte das compilieren der Anwendung noch nicht so richtig.
Ist fleißarbeit...
Zumindest habe ich jetzt eine Option wie man es machen könnte.

von pegel (Gast)


Lesenswert?

hjdasjhskjhdkjashfkja schrieb:
> Ist fleißarbeit...

Das soll es ja eigentlich nicht sein.
Schöner wäre am Anfang des festen Speicherbereichs eine Tabelle nach Art 
der Interrupt Vektoren wie in der startup_xxx die sich dann ich einer 
einfachen .h wiederfindet und die Funktionen direkt findet.

von hjdasjhskjhdkjashfkja (Gast)


Lesenswert?

hi
genau das muss ich erst noch bauen.

ziel soll sein im Feld die Updates klein zu halten ( zeitfaktor )

von temp (Gast)


Lesenswert?

Bei IAR gibt es ein Tool isymexport.exe das aus einer elf-Datei die 
Symbole exportiert und in eine lib erzeugt. Die kann man dann wie 
gewohnt zu seinem Code linken. Damit entfällt die Notwendigkeit einer 
Tabelle mit all den Konsequenzen. Allerdings muss die Zielapp jedesmal 
neu compiliert werden wenn sich an der lib was ändert.

von pegel (Gast)


Lesenswert?

Moin,
ich kämpfe gerade mit der oben erwähnten .h Datei.

Erstellt habe ich bis jetzt eine App1, die beim BluePill die 
Funktions-Adressen-Tabelle und 3 Funktionen ab 0x08010000 ablegt.
Funktioniert alles.

In einer App2 möchte ich diese nutzen. Das Linker Script möchte ich 
nicht ändern. Das hatte ich vor einiger Zeit mal probiert und das hat 
funktioniert. Hier möchte ich aber einfach nur die .h Datei in App2 
einfügen um auf die Tabelle und die Funktionen zuzugreifen.
Den oberen Bereich lediglich lesen und sonst nicht anfassen.

Mit:

#define FNTABLE_OFFSET (uint32_t)0x08010000
uint32_t *fntable=(uint32_t *)FNTABLE_OFFSET;

habe ich einen Zeiger auf die Tabelle und kann mit

  uint32_t a=fntable[0x00];
  uint32_t b=fntable[0x01];
  ....

die Adressen der Funktionen lesen.

Mit allerhand Pointer Experimenten habe ich es nicht geschafft, einen 
Funktionsnamen, ohne Beachtung von Parametern und Rückgabewert, auf die 
richtige Adresse im oberen Bereich zu setzen.
Habe ich in der .ld schon mal vor einiger Zeit gemacht, damit war es mit 
extern ganz einfach und hat funktioniert.

Also die Frage ist:
wie verbinde ich den blanken Funktionsnamen ohne Parameter mit der 
Adresse aus der Funktionstabelle?

von pegel (Gast)


Lesenswert?

Noch vergessen:
Im Linker Script kommt der obere Speicherbereich nicht vor.
Damit wird auch nicht versucht darauf zu schreiben.

von Bauform B. (bauformb)


Lesenswert?

pegel schrieb:
> wie verbinde ich den blanken Funktionsnamen ohne Parameter mit der
> Adresse aus der Funktionstabelle?

Am einfachsten fand ich dieses, das ist eine c-Datei, die wird bei der 
App2 ganz normal mit übersetzt
1
// lib.c 2020-02-28 23:04:40
2
  
3
// DO NOT EDIT -- generated from ../include/syslib.h by mk-lib-tables
4
5
__asm__ (" SYSLIB_VERSION = 0x5E598E78\n .global SYSLIB_VERSION ");
6
7
__asm__ (" abs            = 0x08008078\n .global abs            ");
8
__asm__ (" adc_init       = 0x08008080\n .global adc_init       ");
9
__asm__ (" adc_read       = 0x08008088\n .global adc_read       ");
10
__asm__ (" atoi           = 0x08008090\n .global atoi           ");
11
__asm__ (" beep           = 0x08008098\n .global beep           ");

die syslib.h ist noch normaler, da steht nichts spezielles drin:
1
int   abs (int i);
2
void  adc_init (void);
3
int   adc_read (int channel);
4
int   atoi (const char *text);
5
void  beep (int mHz, int ms);

Die Tabelle in der lib beginnt in diesem Fall auf 0x08008070. Die ersten 
8 Byte sind die Versionsnummer, dann folgen Sprungbefehle zu den 
eigentlichen Funktionen, deshalb sind es 8 Byte pro Funktion. Das ist 
auch wieder Assembler in c verpackt:
1
// lib-table.c 2020-02-28 23:04:40
2
3
// DO NOT EDIT -- generated from ../include/syslib.h by mk-lib-tables
4
5
void __attribute__ ((naked, section ("$syslib_table"), aligned (16)))
6
lib (void)
7
{
8
 __asm__ (" SYSLIB_VERSION = 0x5E598E78\n .global SYSLIB_VERSION");
9
 __asm__ ("lib: .word 0x5E598E78");
10
 __asm__ ("     .word 0xFFFFFFFF");
11
12
 __asm__ ("  ldr pc, [pc]\n  .word   abs        ");
13
 __asm__ ("  ldr pc, [pc]\n  .word   adc_init   ");
14
 __asm__ ("  ldr pc, [pc]\n  .word   adc_read   ");
15
 __asm__ ("  ldr pc, [pc]\n  .word   atoi       ");
16
 __asm__ ("  ldr pc, [pc]\n  .word   beep       ");

: Bearbeitet durch User
von pegel (Gast)


Lesenswert?

Vielen Dank für den Schubs in die richtige Richtung.

Der Sprung in die Funktionen klappt jetzt.
Nur in der Funktion gib es dann ein HardFault, da muss ich noch mal 
sehen...

von Vincent H. (vinci)


Lesenswert?

Das unterste Bit der Adresse muss gesetzt sein, sonst versucht der 
Prozessor das Instruction Set zu wechseln (was er nicht kann) und löst 
eine Exception aus. Im Normalfall sorgt der Compiler dafür dass das Bit 
bei einem Sprung gesetzt wird, in dem Fall aber anscheinend nicht weil 
er die absolute Adresse direkt bekommt...?

: Bearbeitet durch User
von pegel (Gast)


Lesenswert?

Vincent H. schrieb:
> Das unterste Bit der Adresse muss gesetzt sein,

Das stimmt.
Das passiert schon, wenn die Adressen der Funktionen in die fntable[] in 
der App1 eingetragen werden.

von pegel (Gast)


Lesenswert?

Hi,
ich hätte noch eine Frage.
1
void Init_up64k(){
2
  {__asm__ (" LedOn            = 0x0801001D\n .global LedOn             ");}
3
...

Es läuft alles wie es soll. Nur eines hätte ich gern noch.
Ab Adresse 0x08010000 habe ich eine Tabelle mit den Adressen der 
Funktionen.
Ich würde gern für LedOn nicht die Funktionsadresse selbst, sondern den 
Wert aus der Tabelle - Adresse steht in 0x0801000 - eintragen.
Kann mir jemand verraten wie das mit _asm_ geht?

von Erich (Gast)


Lesenswert?

@pegel

Du hast doch deine neue Frage bereits hier gestellt
Beitrag "asm indirekte Addresse zuweisen"

Wäre also gar nicht nötig gewesen, deine neue und zu dem 
Ursprungsbetreff überhaupt nicht passende Frage hier anzuhängen.

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.