Forum: Compiler & IDEs stm32 / gcc - Eingebaute printf übergehen


von Safari (Gast)


Lesenswert?

Hi,

die eingebaute printf-Funktion des gcc ist riesig (~30k), deshalb 
benutze ich schon eine Weile eine Kleinere*.

Angenommen ich habe eine printf-Funktion, die "my_printf" benannt ist.
Nun möchte ich eine Wrapper-Funktion schreiben, die "printf" benannt 
ist.
Ich möchte nun printf, sprintf und snprintf der library übergehen, 
jedoch nicht die ganze library abschalten (z.B. strlen will ich 
behalten).

Wie kann ich das bewerkstelligen?

*hier ein paar Implementationen:
https://github.com/cjlano/tinyprintf
https://github.com/trini/u-boot/blob/master/lib/tiny-printf.c
https://github.com/mpaland/printf
http://www.xappsoftware.com/wordpress/2011/01/17/a-tiny-printf-for-embedded-systems/
http://www.firefly-power.de/ARM/printf.html

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das Stichwort dürfte hier "weak linkage" heißen. Damit kann man eine in 
einer Library verwendete Funktion durch eine andere ersetzen, ohne auf 
die Library verzichten zu müssen.

Voraussetzung ist, daß "printf" in Deiner Standardlibrary als "weak 
symbol" definiert ist, das musst Du also gegebenenfalls anpassen.

http://www.valvers.com/programming/c/gcc-weak-function-attributes/

von foobar (Gast)


Lesenswert?

Einfach die neue printf in eine Datei packen und mitlinken reicht aus. 
Die Version aus der libc wird nur genommen, wenn keine andere vorhanden 
ist.

von Safari (Gast)


Lesenswert?

Das weak linkage, was Rufus schrieb, wird bei mir der Fall sein. Denn, 
wenn ich es so mache, wie foobar schrieb, wird mein printf-wrapper 
verwendet.

Wenn die library-Funktion nicht "weak" ist, dann bekomme ich mit diesem 
Code eine Fehlermeldung a la "already defined", oder?

Vielen Dank für den Denkanstoss, das hat mir schon einiges an 
Kopfzerbrechen bereitet.

von Markus F. (mfro)


Lesenswert?

Safari schrieb:
> Wenn die library-Funktion nicht "weak" ist, dann bekomme ich mit diesem
> Code eine Fehlermeldung a la "already defined", oder?

Nein.

Der Linker holt beim Linken nur die Symbole aus einer Library, die er zu 
dem Zeitpunkt (die Reihenfolge in der Kommandozeile spielt da eine 
Rolle) noch nicht resolved hat. Wenn Du ihm also früher schon (in einer 
Objektdatei, z.B.) ein passendes Symbol anbietest, sucht in in der 
Library gar nicht erst danach.

"Weak"-Symbole braucht man eigentlich nur (dynamisches Linken, das bei 
der µC-Programmierung keine Rolle spielt, mal aussen vorgelassen), wenn 
man eine Default-Implementierung anbieten, aber dem Anwender eine 
Möglichkeit geben will, seine eigene Spezialisierung mitzubringen bzw. 
den Default zu überschreiben (wie z.B. im Startup-Code).

von foobar (Gast)


Lesenswert?

Das mit dem "weak-linkage" ist, wie GNU das typische Verhalten 
implementiert und erweitert hat.

Wenn der Linker nen Symbol sucht, nimmt er die erste Definition, die er 
findet. Dabei wird nicht nur ein Symbol, sondern das gesamte o-File 
dazugelinkt, in dem das Symbol gefunden wurde. Definiert ein o-File 
mehrere Symbole, kann es zu dem "double-defined"-Fehler kommen[1]. Die 
herkömmliche Lösung ist, jedes exportierte Symbol in ein eigenes o-File 
zu packen (d.h. ein File für strlen, eins für strcpy, eins für strncpy, 
etc).

Mit dem weak/strong Attribut hat GNU das Linken erweitert, indem es 
jedem Symbol noch ne Priorität mitgibt. Die Symbole in normalen c-Files 
sind strong, die in Libraries typischerweise weak. Kommen dann ein 
strong und ein oder mehrere weak-Symbole zusammen, gibt es keine 
Fehlermeldung mehr, sondern das strong gewinnt. D.h. aber nicht, dass 
nicht beide Versionen im Programm vorhanden sind, es wird halt nur die 
strong Version benutzt (neuere Linker können unter bestimmten Umständen 
unbenutzte Funktionen wegoptimieren, das ist aber ne weitere 
GNU-Extension).

Normalerweise braucht man sich darum nicht zu kümmern - es klappt 
einfach. Wenn die double-defined Meldung kommt, stimmt normalerweise in 
deinem Programm was nicht und sollte genauer untersucht werden.



[1] Beispiel: strcpy und strncpy sind in einem .o-File im clib. Du 
definierst dir dein eigenes strncpy, das explizit mitgelinkt wird (in 
z.b. mystrncpy.o). Wenn dein Programm nun strcpy (ohne n) benutzt, 
holt der Linker das aus dem clib, leider zusammen mit dem clib-strncpy, 
das ja im gleichen File ist. Peng, double defined strncpy.

von Safari (Gast)


Lesenswert?

Vielen Dank für die ausführlichen Erklärungen. Nun kann ich ruhigen 
Gewissens diverse Funktionen ersetzen und weiss um das Verhalten des 
Linkers.

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
Noch kein Account? Hier anmelden.