Virtual Function Elimination ARM GCC

#6903575
Lesenswert?

Hallo zusammen,

ich versuche, die Code Size meines Binaries möglichst klein zu halten 
und würde deshalb gerne auch virtuelle Funktionen (C++), die nicht 
benutzt werden, aus dem Binary schmeißen. Für normale Funktionen gibt es 
ja Dead Code Elimination des Linkers, aber die greift aufgrund der 
VTables bei virtuellen Funktionen nicht. Stattdessen gibt es anscheinend 
VFE 
(https://developer.arm.com/documentation/dui0474/m/linker-command-line-options/--vfemode-mode), 
was laut Link wohl auch standardmäßig schon aktiviert ist. Jedoch finden 
alle virtuellen Funktionen obwohl ganz klar nicht genutzt, ihren Weg ins 
fertig Binary und verdoppeln dort die Codesize. Compiler: ARM GCC 9.3.1, 
STM32CubeIDE V1.8.0
kompiliert wird mit: -Os -ffunction-sections -fdata-sections 
-Wl,--gc-sections -nostartfiles -nodefaultlibs -nostdlib

Ich habe auch bereits folgende Optionen ohne Erfolg probiert:
-fwhole-program
-flto
-fdevirtualize-at-ltrans

Hat jemand eine Idee, was ich tun muss, um die virtuellen Funktionen 
rauszubekommen (außer, keine zu benutzen...)

Grüße
Gast #6903659
Lesenswert?

Leopold N. schrieb:

> Hat jemand eine Idee, was ich tun muss, um die virtuellen Funktionen
> rauszubekommen (außer, keine zu benutzen...)

Keine zu benutzen, ist natürlich Quatsch.

Die bestmögliche Lösung ist, nur die Funktionen virtuell zu machen, die 
man auch zu nutzen gedenkt und zwar tatsächlich als virtuelle 
Funktionen. Denn logischerweise bringt es nix, eine virtuelle Funktion 
zu deklarieren, die entweder garnicht genutzt wird oder auch nur 
nirgendwo überschrieben wird.
Gast #6903664
Lesenswert?

Zeig mal Beispielcode, prinzipiell kann GCC Optimizer Devirtualization 
(das brauchst du hier efefktiv), aber manchmal weigert er sich. 
Vielleicht ist Amalgation notwendig, obwohl -fwhole-program das gleiche 
bringen sollte.
#6903695
Lesenswert?

Hier als Beispiel mal der LTDC.
Der LTDC wird nur in der Klasse STM32H753BIT6 verwendet, und zwar ist er 
ein Member. Es werden nur die Funktionen LTDC::startup und LTDC::LTDC 
aufgerufen, die restlichen Funktionen landen aber trotzdem aufgrund der 
VTables im Binary.
Angehängte Dateien:
#6903774
Lesenswert?

Hier mal ein STM32CubeIDE Project, mit dem ich das ganze mal ausprobiert 
hab.
Wenn ich bei DerivedClass die Vererbung wegnehme (: public BaseClass 
auskommentieren und override löschen) verschwindet die Funktion 
DerivedClass::foo aus dem Binary, da sie ja auch nicht aufgerufen wird.
Die Funktion DerivedClass::bar bleibt natürlich.
Sobald DerivedClass aber von BaseClass erbt, wird DerivedClass::foo 
immer mit in die Binaries geschleppt, obwohl main() sie nicht aufruft.

Jemand eine Idee?
Angehängte Dateien:
#6903781
Lesenswert?

Leopold N. schrieb:
> Jemand eine Idee?

Haste mal gegoogelt? Wenn dir das keine neuen Ansätze liefert (was es 
nicht tun wird, obwohl die Frage durchaus häufig gestellt wird), gehts 
halt nicht.

Einzige Lösung, die sich dort abzeichnet: Geh zurück auf gcc 3.x. Da 
gabs eine Compileroption für das Problem. Der Erfolg ist nicht 
garantiert, da gcc die ab Version 4 wegen "Nicht-Wartbarkeit" 
(Euphemismus für "funzt nicht wirklich") aufgegeben hat.

Oliver
#6903783
Lesenswert?

Habe gerade gefühlt zwei Tage mit googlen verbracht...
auf GCC 3.x zurückzugehen ist keine Option. Ich kann bloß nicht glauben, 
dass es 2021 (fast 22) keine Möglichkeit geben soll, Dead Code zu 
eliminieren, nur weil ein paar VTables sich darauf referenzieren, welche 
selbst aber nicht gebraucht werden. Und ich versteh nicht, warum VFE als 
Compileroption zwar im Handbuch steht, aber nix tut, bzw. vom Compiler 
sogar explizit nicht erkannt wird.
Gast #6903826
Lesenswert?

Leopold N. schrieb:
> Hier als Beispiel mal der LTDC.

Wir brauchen ein MWE, damit können wir nichts anfangen, weil zu komplex 
und kompiliert nicht.


Leopold N. schrieb:
> Hier mal ein STM32CubeIDE Project, mit dem ich das ganze mal ausprobiert
> hab.
> [...]
> Jemand eine Idee?

Ja, -flto (GCC9) optimiert das sauber wie erhofft:
Es verbleibt nur DerivedClass::foo(). Konstruktor, Destruktor und vtable 
werden komplett eliminiert.
#6903847
Lesenswert?

Leopold N. schrieb:
> Ja, -flto hatte ich auch schon probiert...habe allerdings Sorgen
> bei
> dieser Option, da sie wohl Bugs haben soll (oder mal gehabt hatte in
> früheren Versionen von GCC).

Der Schwippschwager des Onkel meines Bruders Hundesitter kennt jemanden, 
der hat mal gehört, daß…

Debuggen wird damit natürlich nicht einfacher, aber sonstige Sorgen 
braucht man da schon lange nicht mehr zu haben.

Oliver
Gast #6903857
Lesenswert?

Leopold N. schrieb:
> Ja, -flto hatte ich auch schon probiert...habe allerdings Sorgen bei
> dieser Option, da sie wohl Bugs haben soll (oder mal gehabt hatte in
> früheren Versionen von GCC).

Wenn ich den Inhalt von derivedClass.cpp in main.cpp kopiere, klappt es. 
Dann gibt es derivedClass gar nicht mehr im Binary.
Vollte Optimierung bekommt man leider erst mit Amalgation. Soll der TE 
das mal probieren.

LTO bringt grundsätzlich nicht mehr Bugs als GCC sowieso hat, bis auf 
die bekannte Geschichte mit weak linking von interrupts.
#6903903
Lesenswert?

Devirtualization schrieb:
> Wenn ich den Inhalt von derivedClass.cpp in main.cpp kopiere, klappt es.
> Dann gibt es derivedClass gar nicht mehr im Binary.
> Vollte Optimierung bekommt man leider erst mit Amalgation. Soll der TE
> das mal probieren.

Das Problem ist leider, dass ich die virtuellen Klassen und deren 
Ableitungen in verschiedenen Bibliotheken habe und main() davon erst mal 
nichts sieht... Drum geht das mit dem amalgamamatieren leider nicht :)
Gast #6904091
Lesenswert?

> Das Problem ist leider, dass ich die virtuellen Klassen
> und deren Ableitungen in verschiedenen Bibliotheken habe

Falls das der Wahrheit entspricht und es sich um Objektcode-Bibliotheken 
handelt, wirst du doch nicht ernsthaft erwarten daß der Compiler da was 
optimieren kann. Der bekommt den Maschinencode ja nichtmal in die 
Finger.
Gast #6915093
Lesenswert?

Du kannst in Godbolt nicht erkennen, ob der Compiler/Linker Funktionen 
raushaut, oder nicht. Überlege doch mal:
Das Standard-Template ist int square(int num) { return num*num;} was von 
exakt niemanden aufgerufen wird! Und trotzdem ist es im Disassembly - 
egal bei welcher Optimierung usw. Merkste selbst? ;-)

Der Thread stürzt sich hier auf das falsche tool: der Compiler ist 
überhaupt nicht dafür zuständig, Sachen aus dem Programm zu schmeißen! 
Das macht der Linker.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren