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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von hjdasjhskjhdkjashfkja (Gast)


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
vergessen:

Plattform ist Cortex M + GCC

von Jim M. (turboj)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
hi

Danke , schau ich mir an.

von Sid Greybeard (Gast)


Bewertung
-1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
hi
genau das muss ich erst noch bauen.

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

von temp (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


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

von Bauform B. (bauformb)


Bewertung
0 lesenswert
nicht 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
// lib.c 2020-02-28 23:04:40
  
// DO NOT EDIT -- generated from ../include/syslib.h by mk-lib-tables

__asm__ (" SYSLIB_VERSION = 0x5E598E78\n .global SYSLIB_VERSION ");

__asm__ (" abs            = 0x08008078\n .global abs            ");
__asm__ (" adc_init       = 0x08008080\n .global adc_init       ");
__asm__ (" adc_read       = 0x08008088\n .global adc_read       ");
__asm__ (" atoi           = 0x08008090\n .global atoi           ");
__asm__ (" beep           = 0x08008098\n .global beep           ");

die syslib.h ist noch normaler, da steht nichts spezielles drin:
int   abs (int i);
void  adc_init (void);
int   adc_read (int channel);
int   atoi (const char *text);
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:
// lib-table.c 2020-02-28 23:04:40

// DO NOT EDIT -- generated from ../include/syslib.h by mk-lib-tables

void __attribute__ ((naked, section ("$syslib_table"), aligned (16)))
lib (void)
{
 __asm__ (" SYSLIB_VERSION = 0x5E598E78\n .global SYSLIB_VERSION");
 __asm__ ("lib: .word 0x5E598E78");
 __asm__ ("     .word 0xFFFFFFFF");

 __asm__ ("  ldr pc, [pc]\n  .word   abs        ");
 __asm__ ("  ldr pc, [pc]\n  .word   adc_init   ");
 __asm__ ("  ldr pc, [pc]\n  .word   adc_read   ");
 __asm__ ("  ldr pc, [pc]\n  .word   atoi       ");
 __asm__ ("  ldr pc, [pc]\n  .word   beep       ");

: Bearbeitet durch User
von pegel (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.