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
vergessen: Plattform ist Cortex M + GCC
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.
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.
hi Danke , schau ich mir an.
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.
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?
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.
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.
hi genau das muss ich erst noch bauen. ziel soll sein im Feld die Updates klein zu halten ( zeitfaktor )
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.
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?
Noch vergessen: Im Linker Script kommt der obere Speicherbereich nicht vor. Damit wird auch nicht versucht darauf zu schreiben.
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
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...
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
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.
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?
@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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.