In meinem OpenSource Projekt für EBike-Controller geht mir so langsam der Flash-Speicher aus. Der Hersteller des Controllers nutzt einen STM32F103C6, der hat nur 32k Flash. Er nutzt einen Bootloader der sich schon mal 4k nimmt und den ich Kompatibilitätsgründen beibehalten will. Dann brauche ich noch 2k für ein virtuelles EEPROM, es bleiben also nur noch 26k für den eigentlichen Code. Ich compiliere schon mit der Option -Os. Arbeiten tue ich mit der STM32 Workbench, die das Makefile automatisch erzeugt. Da github ja inzwischen auch automatisch über ein Actionscript auf einer virtuellen Maschine compilieren kann, habe ich noch ein eigenes Makefile angelegt, das vom Actionscript bei github genutzt wird, aber natürlich auch lokal auf dem Rechner nutzbar ist. Jetzt stehe ich vor dem Phänomen, daß das von der STM32 Workbench erzeugte bin file deutlich kleiner ist, als das über mein eigenes Makefile (das ich mir Copy Paste aus einem anderen Projekt aus dem Internet zusammengebaut habe, ohne wirklich Ahnung davon zu haben) erzeugte. Beides lokal auf meinem Rechner mit dem gleichen Compiler erzeugt. Wie kann man das automatisiert erzeugte Makefile der Workbench (das Inhalte aus verschiedenen Unterordnern includiert) in ein einzelnes Makefile zusammenfassen, das nicht die Unterordnerstruktur benötigt, sondern nur ein einziges Build-Verzeichnis benötigt, wie es mein selbstgestricktes Makefile macht?! Oder kann man herausfinden warum mein Selbstgestricktes ein größeres Bin-File erzeugt? Selbstgestrickt: https://github.com/EBiCS/EBiCS_Firmware/blob/NCTE/Makefile STM32 Workbench: https://github.com/EBiCS/EBiCS_Firmware/tree/NCTE/make Actions bei github: https://github.com/EBiCS/EBiCS_Firmware/actions Gruß hochsitzcola
Ohne jetzt da groß den Filehaufen durchzuwühlen, findet sich im GitHub-makefile ein -Og, und kein -Os. Oliver
Am besten mal via
1 | make VERBOSE=1 |
vergleichen was letztendlich wirklich an den Compiler übergeben wird.
Oliver S. schrieb: > findet sich im > GitHub-makefile ein -Og Wo? https://github.com/EBiCS/EBiCS_Firmware/blob/b1442a1d6dd32aaaf8c3c02ffb86795cf8afdce4/Makefile#L25 Gruß hochsitzcola
Hab ich mir jetzt angeschaut, sind aber böhmische Dörfer für mich. Ich habe die beiden Versionen mal angehangen.... Gruß hochsitzcola
EBiCS_Firmware.map:
1 | .isr_vector 0x08001000 0x10c |
2 | .text 0x0800110c 0x5aec |
output.map:
1 | .isr_vector 0x08000000 0x10c |
2 | .text 0x0800010c 0x591c |
.text ist das eigentliche Programm, einmal 23276 Byte groß und einmal 22812. Ist das "deutlich kleiner"? Oder kommt der große Unterschied von der unterschiedlichen Methode: stat "build/EBiCS_Firmware.bin" vs. arm-none-eabi-size "LishuiFOC_01.elf" Und überhaupt: warum .bin? In den diversen hex-Formaten stehen die Adressen mit drin. Das ist durchaus vorteilhaft wenn es einen Offset für den Bootloader gibt. Außerdem fängt das obere erst 4K später an und entsprechend fehlen am Ende 4K. Da ist wohl der Bootloader versteckt? Dann funktioniert das so wie in output.map doch nicht?
ich lasse die bin Dateien nur erzeugen, um die tatsächliche Größe des Codes im Flash ausgeben zu lassen, darum auch der stat Befehl. Beim compilieren auf github habe ich ja keinen direkten Zugriff auf die bin Datei, da gleich die verschlüsselte Datei für den Bootloader als Artifakt ausgegeben wird. Da ist es auch ein Vorteil, daß die bin Datei keine Adress-Information beinhaltet, da kann ich gleich die Dateigrößen vergleichen und muß nicht den Offset von der Startadresse rausrechnen... Das was arm-none-eabi-size als txt ausgibt, ist ja nicht die tatsächliche Größe im Flash. Die 400 Byte unterschied mag einem nicht viel erscheinen, wenn es aber darum geht, ein Feature noch in den Code reinzubekommen oder nicht, können sie entscheidend sein ;-) Gruß hochsitzcola https://github.com/EBiCS/EBiCS_Firmware/runs/5962771990?check_suite_focus=true
1 | arm-none-eabi-size build/EBiCS_Firmware.elf |
2 | text data bss dec hex filename |
3 | 25752 72 2760 28584 6fa8 build/EBiCS_Firmware.elf |
4 | arm-none-eabi-objcopy -O ihex build/EBiCS_Firmware.elf build/EBiCS_Firmware.hex |
5 | arm-none-eabi-objcopy -O binary -S build/EBiCS_Firmware.elf build/EBiCS_Firmware.bin |
6 | make --no-print-directory post-build |
7 | code size in flash: |
8 | stat "build/EBiCS_Firmware.bin" |
9 | File: build/EBiCS_Firmware.bin |
10 | Size: 25824 Blocks: 56 IO Block: 4096 regular file |
11 | Device: 801h/2049d Inode: 1317766 Links: 1 |
Der Parameter -Os beeinflusst nur einige Optimierungsschritte. Im Extremfall kann es sogar passieren, dass dein Programm mit diesem Parameter kein einziges Byte kleiner Wird. Ich habe das Gefühl, dass du einen viel größeren Effekt erwartest, wie bei einer ZIP Kompression. Darauf kannst du aber lange warten.
Stefan ⛄ F. schrieb: > Der Parameter -Os beeinflusst nur einige Optimierungsschritte. Im > Extremfall kann es sogar passieren, dass dein Programm mit diesem > Parameter kein einziges Byte kleiner Wird. Abgesehen davon, daß das eher nicht stimmt, ist die eigentlich Frage des TO ja, warum es trotz angeblich identischer makefiles Unterschiede gibt. Da gibts eigentlich nur eine Lösung: Compiler- und Linkeraufrufe vergleichen. Eventuell vorher noch ein -v spendieren. Oliver
hochsitzcola schrieb: > Das was arm-none-eabi-size als txt ausgibt, ist ja nicht die > tatsächliche Größe im Flash. Soweit ich weis ergibt sich der Flash Bedarf aus "text" (Programmcode) plus "data" (Startwerte für Variablen). https://mcuoneclipse.com/2013/04/14/text-data-and-bss-code-and-data-size-explained/
Ich habe nicht behauptet, das die makefiles identisch sind, sie sind deutlich unterschiedlich. Was ich nicht weiss, welche Option oder welcher Befehl im Makefile den Unterschied in der erzeugten Codegrösse verursacht, bzw. wie man das STM Makefile mit den includes zu einem zusammenfasst. Gruß hochsitzcola
hochsitzcola schrieb: > Da ist es auch ein Vorteil, daß die bin Datei keine Adress-Information > beinhaltet, da kann ich gleich die Dateigrößen vergleichen und muß nicht > den Offset von der Startadresse rausrechnen... > Das was arm-none-eabi-size als txt ausgibt, ist ja nicht die > tatsächliche Größe im Flash. Nicht die Startadresse raus rechnen, sondern text und data zusammenzählen, dann kommt das ungefähr hin ;) Die meisten Funktionen sind gleich groß, hier mal die unterschiedlich großen. Vielleicht sieht jemand einen Zusammenhang.
1 | EBiCS_Firmware.map output.map |
2 | ------------------------------------ -------------------------- |
3 | |
4 | FOC.o 0x90 FOC.o 0x90 |
5 | FOC.o 0xb8 FOC.o 0xb8 |
6 | FOC.o 0x1a4 | FOC.o 0x198 |
7 | |
8 | display_kingmeter.o 0x18 | display_kingmeter.o 0x1b |
9 | display_kingmeter.o 0x40 display_kingmeter.o 0x40 |
10 | display_kingmeter.o 0xac | display_kingmeter.o 0xa0 |
11 | display_kingmeter.o 0x448 | display_kingmeter.o 0x3e4 |
12 | |
13 | print.o 0x20 | print.o 0x2c |
14 | print.o 0x24 | print.o 0x24 |
15 | print.o 0x88 | print.o 0xbe |
16 | print.o 0xfe | print.o 0x126 |
17 | |
18 | stm32f1xx_hal_msp.o 0x18 | stm32f1xx_hal_msp.o 0x1b |
19 | stm32f1xx_hal_msp.o 0x40 stm32f1xx_hal_msp.o 0x40 |
20 | stm32f1xx_hal_msp.o 0xb4 stm32f1xx_hal_msp.o 0xb4 |
21 | stm32f1xx_hal_msp.o 0xb8 stm32f1xx_hal_msp.o 0xb8 |
22 | stm32f1xx_hal_msp.o 0xd8 stm32f1xx_hal_msp.o 0xd8 |
23 | stm32f1xx_hal_msp.o 0x104 stm32f1xx_hal_msp.o 0x104 |
24 | |
25 | system_stm32f1xx_Bootloader.o 0x8 | system_stm32f1xx.o 0x18 |
26 | system_stm32f1xx_Bootloader.o 0x10 | system_stm32f1xx.o 0x4c |
27 | system_stm32f1xx_Bootloader.o 0x4c |
28 | |
29 | |
30 | |
31 | main.o 0x2 main.o 0x2 |
32 | main.o 0xc main.o 0xc |
33 | main.o 0xc main.o 0xc |
34 | main.o 0xc main.o 0xc |
35 | main.o 0xc | main.o 0x10 |
36 | main.o 0x20 | main.o 0x24 |
37 | main.o 0x20 |
38 | main.o 0x29 main.o 0x29 |
39 | main.o 0x2e main.o 0x2e |
40 | main.o 0x64 main.o 0x64 |
41 | main.o 0x70 |
42 | main.o 0x78 |
43 | main.o 0x7c main.o 0x7c |
44 | main.o 0x80 | main.o 0x84 |
45 | main.o 0xa8 | main.o 0xb8 |
46 | main.o 0xac | main.o 0x138 |
47 | main.o 0x150 | main.o 0x1c8 |
48 | main.o 0x1fc | main.o 0x1dc |
49 | main.o 0x268 | main.o 0x27c |
50 | main.o 0x2dc | main.o 0xa8c |
51 | main.o 0xb48 |
hochsitzcola schrieb: > bzw. wie man das STM Makefile mit den includes zu einem > zusammenfasst. Mit etwas Verständnis, was include macht, und einem Texteditor. Bleibt die Frage, warum? Das löst dein Problem auch nicht. Es hilft alles nichts, du wirst vergleichen müssen, wie und was da jeweils compiliert und gelinkt wird. Oliver
Oliver S. schrieb: > Mit etwas Verständnis, was include macht, und einem Texteditor. Ich habe schon versucht, mit einem Texteditor einfach den Inhalt der includierten Files in das Makefile rüberzukopieren, aber dann gibt es immer Fehlermeldungen beim compilieren. Die erforderliche Syntax in makefiles gibt mir immer Rätsel auf. Die tausenden Zeilen C-Code habe ich hinbekommen, am Makefile scheitere ich ...😉 Oliver S. schrieb: > Bleibt die Frage, warum? Das löst dein Problem auch nicht. Doch, dann würde ich ja das kleinere bin File bei git erzeugen können.... Gruß hochsitzcola
hochsitzcola schrieb: > am Makefile scheitere ich Ist auch nicht einfach. Nun sind normale Desktop Computer inzwischen so schnell, dass die Haupt-Funktion von Make (für die µC Projekte) überflüssig geworden ist: Nur die geänderten Dateien (und was davon abhängt) zu compilieren. Meine Meinung nach ist es keine Schande, wenn man einfach ein Batch File (Shell Script) benutzt, wo die nötigen gcc Aufrufe untereinander aufgelistet sind.
Stefan ⛄ F. schrieb: > Meine Meinung nach ist es keine Schande, wenn man einfach ein Batch File > (Shell Script) benutzt, wo die nötigen gcc Aufrufe untereinander > aufgelistet sind. Das mache ich schon seit langen Jahren so. Aber mal was anderes: wenn man tatsächlich knapp an Flash ist, dann wären 2 Maßnahmen zu bedenken: 1. Änderungen in den Quellen. Also z.B. keine ausschweifenden HAL-Routinen oder so, sondern dem Projekt angepaßte eigene Routinen. 2. nicht den GCC benutzen, sondern stattdessen den Keil. Der hat nach meiner Erfahrung schon vor 10 Jahren einen deutlich besseren und kürzeren Maschinencode als der GCC gemacht. Da dieses Projekt nicht über 32K geht, sollte das überhaupt kein Problem sein. Allerdings nehme ich mal an, daß der GCC mittlerweile etwas aufgeholt hat. Da darf man keine Wunder erwarten. W.S.
Irgendwo habe ich mal gelesen, dass der gcc kompakteren Code erzeugt, wenn man nicht jede *.c Datei einzeln compiliert, sondern alle zusammen in einem einzigen Aufruf. Ob das stimmt, weiß ich allerdings nicht.
Der gcc kann’s ja problemlos. Der TO rätselt nur, wie. Oliver
Mir fallen da noch diese Flags ein: -ffunction-sections -fdata-sections -flto -Wl,--gc-sections Ich weiß nicht genau, was sie bewirken. Es ging wohl primär darum, dass unbenutzte Funktionen weg optimiert werden.
Oh, das -flto scheint ein scharfes Schwert zu sein :-) stat "build/EBiCS_Firmware.bin" File: build/EBiCS_Firmware.bin Size: 14556 Blocks: 32 IO Block: 4096 regular file Device: 0h/0d Inode: 0 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1000/gaswerke) Gid: ( 1000/gaswerke) Access: 2022-04-24 20:20:54.000000000 Modify: 2022-04-24 20:20:54.000000000 Change: 2022-04-10 17:14:12.000000000 Ob der Code damit noch läuft habe ich aber nicht ausprobiert :-) Gruß hochsitzcola
Stefan ⛄ F. schrieb: > Ob das stimmt, weiß ich allerdings nicht. Stefan ⛄ F. schrieb: > Ich weiß nicht genau, was sie bewirken. So ganz scheinst du da nicht im Thema zu sein, oder? Oliver
Stefan ⛄ F. schrieb: > Ist auch nicht einfach. Nun sind normale Desktop Computer inzwischen so > schnell, dass die Haupt-Funktion von Make (für die µC Projekte) > überflüssig geworden ist: Nur die geänderten Dateien (und was davon > abhängt) zu compilieren. > > Meine Meinung nach ist es keine Schande, wenn man einfach ein Batch File > (Shell Script) benutzt, wo die nötigen gcc Aufrufe untereinander > aufgelistet sind. Fürs Testen darf man das gerne tun. Aber Den Vorteil durch Parallelisierung merkt man recht schnell, vor allem wenn man die ST Bibliothek nutzt und die immer mit baut. Rebuild eines kleinen STM32 Projekts (64KiB Binary, 53 Quelltextdateien) auf einem Ryzen 1600: 7.7s Single Core, 1.6s mit Parallelisierung. 0.26s bei partiellem Rebuild einer Datei. Und ja, 7.6s bei jedem Syntaxfehler kommt einem lang vor. Stefan ⛄ F. schrieb: > Irgendwo habe ich mal gelesen, dass der gcc kompakteren Code erzeugt, > wenn man nicht jede *.c Datei einzeln compiliert, sondern alle zusammen > in einem einzigen Aufruf. Das lässt sich recht einfach erklären: Ist sämtlicher Code in einer Datei, kann der Compiler Funktionen leicht Inlinen, was bei Funktionen, die nur einmal verwendet werden, immer von Vorteil ist, da mindestens Prolog und Epilog eingespart werden. Ist der Code hingegen in einer anderen Datei, geht das nicht - der Linker macht nie ein Inline. Man kann natürlich mogeln und das in einen Header als Inline auslagern, aber dann geht der Speicherverbrauch um so stärker nach oben, sobald die Funktion aus zwei Dateien verwendet wird. Alternativ kann man auch noch bei einem einzigen gcc Aufruf direkt alle Quelltextdateien übergeben. Aber ansonsten: 1. Vergleich die Compileraufrufe, die werden bei Make ja normalerweise vollständig mit ausgegeben. 2. Schau, ob newlib und gcc die gleiche Version haben. 3. Mit readelf --all *.elf lassen sich auch alle Symbole und deren Platzverbrauch in dem Binary anzeigen. 4. Nicht printf aus der newlib verwenden. Das braucht im Gegensatz zur Implementierung in der avr-libc leider malloc und free und wenn man die eigentlich nicht braucht, wird das Binary dadurch unnötig groß. 5. Die ST Bibliothek nimmt einem zwar eine Menge Arbeit ab und ist ein passables how-to bei komplexerer Peripherie. Selber schreiben erzeugt aber dann meist doch kompakteren Code.
:
Bearbeitet durch User
Malte _. schrieb: > Ist der Code hingegen in einer > anderen Datei, geht das nicht - der Linker macht nie ein Inline. Und deshalb wurde vor inzwischen doch schon längerer Zeit Link time optimization erfunden, kurz lto. Ist zwar im Falle vom gcc/clang nicht ganz zutreffend, weil die Optimierung trotzdem vom Compiler durchgeführt werden, der ist aber sozusagen in den Linker gerutscht, und sieht dort den gesamtem Code. Oliver
Oliver S. schrieb: > So ganz scheinst du da nicht im Thema zu sein, oder? Das ist wahr. C nutze ich nur gelegentlich im Rahmen meines Hobbies. Es freut mich aber, dass ich dem TO dennoch helfen konnte. > Den Vorteil durch Parallelisierung merkt man recht schnell > 7.6s bei jedem Syntaxfehler kommt einem lang vor. Du bist ja verwöhnt. Compiliere mal SAP E-Commerce, dabei stirbst du vor Langeweile. 15 Minuten sind da ganz normal (mit clean mehr als 45 Minuten).
Meinten Sie: 15 Stunden? Das kommt ungefähr hin, für das offizielle GCC/binutils/newlib Paket von ARM :( Sollte ich eigentlich mal wieder einplanen.
Stefan ⛄ F. schrieb: > Es freut mich aber, dass ich dem TO dennoch helfen konnte. Hat leider nicht geholfen, die bin Datei ist zwar klein, läuft aber auch nicht :-( Gruß hochsitzcola
-flto ist die Link time optimisation. Die schmeißt Recht viel unnützes raus ist aber je nach gcc Version problematisch gerade wenn sich Adressen während des linkens verschieben und sich externer Code auf diese Adressen verlässt. Was geht denn mit lto nicht? Bootet nicht oder verbindet sich nicht mit deinem Java Tool? -ffunction-sections -fdata-sections Bringt nix für Code size bestimmt nur das Daten und Institutionen von Funktionen nicht wahllos verteilt werden. -Wl,--gc-sections Das entfernt toten Code. Also Funktionen die nicht verwendet werden. Ansonsten musst du das map file durch gehen. Ggf lohnt es sich das Projekt in der stmcubeide zu importieren dort gibt es einen Recht brauchbaren Screen der das map file in einem GUI auf drösselt. Dann kannst dir große Funktionen ansehen und ggf. Optimieren.
hochsitzcola schrieb: > Stefan ⛄ F. schrieb: >> Es freut mich aber, dass ich dem TO dennoch helfen konnte. > > Hat leider nicht geholfen, die bin Datei ist zwar klein, läuft aber auch > nicht :-( > > Gruß > hochsitzcola Es kann sein, dass der gcc mit -flto Interruptroutinen wegoptimiert, wenn diese in einem Assembler File als weak deklariert werden. https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 Bin da auch schon mal drüber gestolpert, anscheinend sollte es funktionieren, entweder die deklarationen der Interruptfunktionen und Vektortabelle generell in C zu machen, oder die Reihenfolge der Objekte beim Linken zu ändern.
> Meinten Sie: 15 Stunden? Das kommt ungefähr hin, für das offizielle > GCC/binutils/newlib Paket von ARM :( Das klingt irgendwie nach angezogener Handbremse. Ich baute ein komplettes Linux inklusive X11, Qt und diverser Tools (bash, xterm, systemd, python, ..), inklusive Host-Toolchain, Host-Cross-Toolchain und Canadian-Cross-SDK (inklusive Qt) in gut 3 Stunden Realzeit (ohne vorcompilierte Binaries, alles direkt aus den Sourcecodes). Auf einem Quadcore+Hyperthreading, zugegeben, aber doch um ein paar Größenordnungen umfangreicher als gcc/binutils/newlib für ARM kommt mir vor.
g457 schrieb: >> Meinten Sie: 15 Stunden? Das kommt ungefähr hin, für das offizielle >> GCC/binutils/newlib Paket von ARM :( > > Das klingt irgendwie nach angezogener Handbremse. > ... 3 Stunden ... auf einem Quadcore+Hyperthreading... 4 Kerne hätte ich auch, aber auch eine langsame Notebook-Platte. Dank newlib produziert der build nämlich 18GB (acht zehn Giga Byte) -- wenn man alles abwählt, was offiziell abzuwählen ist. Vollkommen krank das. Hat evt. jemand einen Tipp, wie man verhindern kann, dass newlib gebaut wird? Noch eine Anekdote, nicht ganz so OT: Alex D. schrieb: > anscheinend sollte es funktionieren, entweder die deklarationen > der Interruptfunktionen und Vektortabelle generell in C zu machen Hier habe ich ein Beispiel wo ungefähr das Gegenteil passiert, obwohl praktisch alles C ist, auch die Vektortabelle und die crt0. Im ersten Versuch mit -flto -Os blieb kein einziges Byte C übrig, nur ein paar winzige Assembler Funktionen. Dagegen hilft ein attribute used für jede spezielle section (wie z.B. die Vektortabelle). Dann "optimiert" der GCC mit -flto -Os von 19360 auf 19448 Byte :) Ein anderes Programm wird tatsächlich kleiner, ca. 8K auf 7K. Allerdings kann man unmöglich feststellen, was fehlt. objdump ist nutzlos, es gibt keine Ähnlichkeit mit einem "normalen" Programm. Und ein paar Kleinigkeiten gehen verloren, z.B. align 8 aus dem Linker Script. Oder Daten, die nachträglich ins Hex-File eingetragen werden, z.B. CRC oder Datum. Anscheinend merkt der lto, dass konstante Daten aus der struct geladen werden und ändert das in ein immediate. Das ist aber auch von den Daten selbst abhängig. lto optimiert scheinbar vor allem auf Geschwindigkeit, dass es manchmal kleiner wird, ist ein Nebenprodukt. Aber warum sollte man das für ein komplettes Programm machen? Und wie passt das schlechtere alignment der text section dazu? Ist evt. -Wl,--gc-sections die bessere Lösung? Hat -ffunction-sections etwas damit zu tun?
Alex E. schrieb: > Was geht denn mit lto nicht? Es geht schlichtweg garnichts, keinerlei Lebenszeichen vom Controller. Ich habe es aber auch nicht weiter analysiert. Mir würde es ja vollkommen reichen, wenn ich das Makefile mit den includes aus der STM32 Workbench so umschreiben könnte, daß es in der obersten Ebene des Projektverzeichnisses liegt und funktioniert. Dann wäre ich ja schon glücklich ;-) Gruß hochsitzcola
Anfrage der Art "ich habe zwar keine Ahnung, aber irgendwo irgend eine Software heruntergeladen, die irgendwie für irgendwas kompiliert, Hilfe, es funzt nicht" bekommen halt selten sinnvolle Antworten. Ist so. Oliver
Oliver S. schrieb: >> Ich weiß nicht genau, was sie bewirken. > So ganz scheinst du da nicht im Thema zu sein, oder? Oliver, ich denke du kannst die jüngsten Fragen des TO beantworten. Schau sie dir mal an.
Stefan ⛄ F. schrieb: > jüngsten Fragen Welche denn genau? Und nein, ich schreibe für das Projekt keine neues makefile. Oliver
Oliver S. schrieb: > Und nein, ich schreibe für das Projekt keine neues makefile. Sollst du ja auch nicht :-) Das mache ich schon selber. Ich werde zunächst versuchen, die vom Makefile inkludierten Dateien aus dem Debug-Verzeichnis in die zugehörigen Projektverzeichnisse zu kopieren und die Pfade im Makefile entsprechend anzupassen.... Gruß hochsitzcola
Vincent H. schrieb: > Am besten mal via > make VERBOSE=1 > > vergleichen was letztendlich wirklich an den Compiler übergeben wird. Machen. Und dann vergleichen. Oliver
Bauform B. schrieb: > lto optimiert scheinbar vor allem auf Geschwindigkeit, dass es manchmal > kleiner wird, ist ein Nebenprodukt. Das kann ich so nicht nachvollziehen. LTO ansich optimiert ja auch garnix. Es sorgt nur dafür das die Optimierungen nicht zur Compilezeit sondern erst zur Linkzeit erfolgen. Dazu wird in die einzelnen Objektdateien kein Binärcode sondern ein Zwischencode geschrieben. Je nach GCC-Version und Optionen wird der Zwischencode auch zusätzlich in die Objekte geschrieben. Die Optimierung findet dann erst beim Linken statt. Deshalb muss auch beim Linken die Optimierungsoption (z.B. -Os) angegeben werden genauso wie -flto. Wird -flto nur beim Compilieren angegeben kann LTO evtl. garnicht greifen wenn die Objekte auch Binärcode enthalten. > Ist evt. -Wl,--gc-sections die bessere Lösung? Hat -ffunction-sections > etwas damit zu tun? Beide Optionen werden bei korrekter Verwendung von LTO keinen Vorteil bringen. Wenn doch stimmt was nicht. Wir haben die Erfahrung gemacht das LTO grundsätzlich zu besserem (kleiner, schneller) Code führt, verdeckte Bugs an die Oberfläche bringt und kaum noch debugbare ELF-Dateien erzeugt (zumindest mit -Os) YMMV :-)
Μαtthias W. schrieb: > Die Optimierung findet dann erst beim Linken > statt. Die Optimierung findet schon beim Compilieren statt, nur wird der Compiler halt im "link-Schritt" vor dem linker nochmals aufgerufen. > Deshalb muss auch beim Linken die Optimierungsoption (z.B. -Os) > angegeben werden genauso wie -flto. Wird -flto nur beim Compilieren > angegeben kann LTO evtl. garnicht greifen wenn die Objekte auch > Binärcode enthalten. Das war nur bei den allerersten gcc's mit lto der Fall. Seit gcc 4.9 klappt das alles, ohne dem "linker" die Optimierungsflags nochmals mitgeben zu müssen (und seit gcc 5 ignoriert der eventuell doch mitgegebene einfach) Oliver
:
Bearbeitet durch User
Oliver S. schrieb: > Μαtthias W. schrieb: >> Die Optimierung findet dann erst beim Linken >> statt. > > Die Optimierung findet schon beim Compilieren statt, nur wird der > Compiler halt im "link-Schritt" vor dem linker nochmals aufgerufen. Erbsenzählerei :-) $ gcc -o test a.o b.o ist jetzt aus meiner Sicht schon das Linken. Aber lassen wir das >> Deshalb muss auch beim Linken die Optimierungsoption (z.B. -Os) >> angegeben werden genauso wie -flto. Wird -flto nur beim Compilieren >> angegeben kann LTO evtl. garnicht greifen wenn die Objekte auch >> Binärcode enthalten. > > Das war nur bei den allerersten gcc's mit lto der Fall. Seit gcc 4.9 > klappt das alles, ohne dem "linker" die Optimierungsflags nochmals > mitgeben zu müssen (und seit gcc 5 ignoriert der eventuell doch > mitgegebene einfach) In der Tat. Auch -flto kann beim Linken entfallen. Da kann ich meine Makefiles wohl etwas entschlacken. Matthias
Μαtthias W. schrieb: > Erbsenzählerei :-) > $ gcc -o test a.o b.o > ist jetzt aus meiner Sicht schon das Linken. Aus meiner auch - wenn ohne lto ;) mit lto ruft das gcc-frontend da collect2 auf, und das ist letztendlich der Compiler. ld kommt dann danach. Oliver
:
Bearbeitet durch User
Oliver S. schrieb: > Stefan ⛄ F. schrieb: >> Ob das stimmt, weiß ich allerdings nicht. > > Stefan ⛄ F. schrieb: >> Ich weiß nicht genau, was sie bewirken. > > So ganz scheinst du da nicht im Thema zu sein, oder? > > Oliver JA! Mich wundert immer wieder wie wenig Stefan weiß, aber trotzdem immer ganz vorne mit quatschen muss bei allem. Es ist ja ok wenn man sich mit manchen Sachen nicht auskennt, aber dann halt doch mal den Rand Stefan.
Hm, ich habe es soweit hinbekommen, das es lokal auf dem Windowsrechner läuft, auf der virtuellen Linux-Maschine bei github mag es nicht. :-( https://github.com/EBiCS/EBiCS_Firmware/runs/6179455665?check_suite_focus=true [c]Building target: LishuiFOC_01.elf Invoking: MCU GCC Linker arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -mfloat-abi=soft -L Drivers/CMSIS -specs=nosys.specs -specs=nano.specs -T"STM32F103C6Tx_FLASH_Bootloader.ld" -Wl,-Map=output.map -Wl,--gc-sections -o "build/EBiCS_Firmware.elf" @"objects.list" -larm_cortexM3l_math -lm arm-none-eabi-gcc: error: build/startup_stm32f103x6.o: No such file or directory make: *** [makefile:39: LishuiFOC_01.elf] Error 1 Error: Process completed with exit code 2.[/] Das wird wohl irgendwas mit den Pfaden auf der virtuellen Maschine zu tun haben.... Gruß hochsitzcola
Die startup_stm32f103x6.s ist ein Assembler File und das wird nicht gebaut da hat make schon Recht. Was er dir da sagt ist zum linken brauche ich build/startup_stm32f103x6.o Aber ich weiß nicht wie ich dahin komme. Wie ist denn die rule im makefile für %.s?
Ah, ich sehe jetzt schon einen Unterschied, auf dem Windowsrechner ist das der erste Schritt beim Compilieren:
1 | Building file: Startup/startup_stm32f103x6.s |
2 | Invoking: MCU GCC Assembler |
3 | |
4 | arm-none-eabi-as -mcpu=cortex-m3 -mthumb -mfloat-abi=soft -g -o "build/startup_stm32f103x6.o" "Startup/startup_stm32f103x6.s" |
5 | Finished building: Startup/startup_stm32f103x6.s |
in dem Output des Actionscripts bei github fehlt dieser Schritt :-( Gruß hochsitzcola
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o))) vpath %.c $(sort $(dir $(C_SOURCES))) # list of ASM program objects OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o))) vpath %.s $(sort $(dir $(ASM_SOURCES))) Dieser Bereich ist ggf. Ungünstig. Ich hätte beide in einer Zuweisung gemacht.
Fehler gefunden :-) ein Ordnername war im makefile klein geschrieben, Windows ist das egal, Linux mag das natürlich nicht... Die bei github genutzte Compiler-Version erzeugt sogar noch kleineren Code als die auf meinem Windowsrechner
1 | stat "build/EBiCS_Firmware.bin" |
2 | File: build/EBiCS_Firmware.bin |
3 | Size: 25292 Blocks: 56 IO Block: 4096 regular file |
4 | |
5 | stat "build/EBiCS_Firmware.bin" |
6 | File: build/EBiCS_Firmware.bin |
7 | Size: 25508 Blocks: 56 IO Block: 4096 regular file |
jetzt habe ich wieder 1k Luft für weitere Features in der Firmware ;-) Gruß hochsitzcola
Jetzt hast du es immerhin geschafft, uns die Aufrufe vom Linker und Assembler zu zeigen, dem eigentlich relevanten Aufruf des Compilers aber immer noch nicht. Olivet
Über kurz oder lang muss die Hal von ST da raus die Frist nur Code und Laufzeit.
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.