printf() Marke Eigenbau
« | 05 Jun 2022 | »Und Schuld hat
libsupc++
…
… dass ich jetzt auch noch printf()
und seine Freunde nachbauen darf.
Und so beginnt ein weiterer Tag meiner Reise ins EFI-Land.
Mit dem GCC werden C++ Exceptions in EFI Apps kein Problem mehr sein.
dachte ich. Tja, falsch gedacht.
Das alte Problem, dass C++ Exception Handler und RTTI
jede Menge im
Hintergrund ausführen, der in der C-Runtime verankert ist, verfolgt mich
nun nicht nur am MSVC
sondern auch im GCC Build.
Grundsätzlich gibt es dort zwar eine Trennung von Kernfunktionen und
Runtime-Zusätzen. Und zwar bietet die libsupc++
einige Basis
Unwinding-Routinen an, doch diese greifen auf jede Menge C Funktionen
zu, die es in nativen EFI Apps nicht gibt.
In Foren ließt man dann, man könnte die Bibliothek und Teile der
glibc
anpassen und sich neu zusammenkompilieren, doch dann schaffe
ich wieder Code, der im MSVC explizit ausgeblendet werden muss.
Unabhängige printf(), sprintf() und fprintf() Funktionen
Das Problem sind tiefe Verschachtelungen zwischen String-Funktionen und den Betriebssystem-Primitiven.
Wenn eine printf()
Implementierung direkt ein write
auf STDOUT
beinhaltet, ist das zwar effizient, aber nur
POSIX
oder Linux tauglich.
Das gleiche gilt dann auch für die WinAPI am MSVC.
Und schlimmer wird es, wenn im Code dann noch Compiler-spezifische
Erweiterungen benutzt werden.
Ich brauche also ein printf()
, das Zeichen für Zeichen an einen Callback
schickt. Und dieser Callback kann dann einfach an EFI oder etwas
anderes angepasst werden. sprintf()
und fprintf()
funktionieren
genau so, nur dass noch ein Parameter angefügt wird, der eine Referenz
zum String oder zum FILE Objekt mitführt.
Und eben mit dieser Aufgabe werde ich wohl etwas Zeit verbringen müssen,
denn erst wenn man seine Implementierung startet, merkt man, dass
printf
gar nicht so “unkomplex” ist, wenn die unterschiedlichen
Format-Spezifizierer kombiniert werden müssen.
Und wozu das Ganze?
Der GCC produziert interne Funktionen für z.B. purecall
oder cast Fehler und
diese nutzen offenbar printf()
und fprintf()
und sprintf()
um Debugging
Nachrichten auf die Konsole zu schreiben.
Und dann wird beim Linken sichtbar, dass das unresolvable symbol printf
nicht in cxx_purecall_xyz
aufgerufen werden kann.
Während es mir (mehr oder weniger) gelungen ist, andere Bibliotheken von
zlib
bis zur libjpeg
so abzuspecken, dass sie nur noch ihre Algorithmen
umsetzen und keine OS-Funktionen aufrufen, zwingt mich jetzt ausgerechnet
der C++ Compiler selbst, diese C-Schnittstelle auch in EFI nachzubauen.
Die Bibliothek GNU-EFI hätte zwar eine
eigene Print()
Implementierung, doch diese arbeitet nur mit wchar_t
und
unterstützt nicht alle Refinessen von printf()
.
Mich enttäuscht daher, dass sich dieses Verhalten nicht “leichter” abschalten lässt.
Fazit
Aber etwas Gutes hat es am Ende:
Früher oder später habe ich die Sourcen für einen kleinen Betriebssystemkern beieinander.
Denn wenn man alle STD-C Funktionen selbst implementiert hat, kann man viele Fremdprogramme damit neu kompilieren und sie über die “eigene Schnittstelle” laufen lassen.