Standardfunktion ersetzen
-
'Standardfunktion ersetzen' ist generell eine schlechte Idee,
#define dafür zu benutzen, erst recht.
-
dachschaden schrieb:
SeppJ schrieb:
Wenn man's drauf anlegt, dann geht das sicher auch auf Compiler-/Linkerebene. Dem Compiler verbieten, Intrinsics zu benutzen, dann beim Linken dem Linker eine Bibliothek mit den eigenen Standardfunktionen und einer höheren Priorität als die Symbole aus der Standardbibliothek geben.
Sollte ein Compiler nicht eh (außer bei abnorm hohem Optimierungslevel - bei dem ich schon die eine oder andere Warnung für vom Compiler generiertem Code bekommen habe :D) nicht eh immer alles in eine eigene Funktion packen, wenn diese nicht in irgendeiner Art und Weise als inline deklariert wurde?
Das Inlining von Standardfunktionen ist ziemlich normal. Typisches Beispiel zum Beispiel der GCC mit mathematischen Funktionen, wo bei statischen Werten direkt das Ergebnis eingesetzt wird, man die Mathebibliothek nicht einmal mehr braucht. Andere Sachen, die gerne und frühzeitig geinlined werden sind performcancekritische, einfache Funktionen, also memcpy und vergleichbares. Genau, wonach der TE fragt. Auch schon oft gesehen sind diverse Optimierungen bei Ausgabefunktionen, wie
printf("%s\n", s)
zuputs(s)
(wobei der puts-Aufruf aber natürlich nicht geinlined wird) und ähnliches.Wutz schrieb:
'Standardfunktion ersetzen' ist generell eine schlechte Idee,
Warum? Die sind doch nicht heilig. Sind Funktionen wie alle anderen auch.
-
SeppJ schrieb:
Das Inlining von Standardfunktionen ist ziemlich normal. Typisches Beispiel zum Beispiel der GCC mit mathematischen Funktionen, wo bei statischen Werten direkt das Ergebnis eingesetzt wird, man die Mathebibliothek nicht einmal mehr braucht. Andere Sachen, die gerne und frühzeitig geinlined werden sind performcancekritische, einfache Funktionen, also memcpy und vergleichbares. Genau, wonach der TE fragt. Auch schon oft gesehen sind diverse Optimierungen bei Ausgabefunktionen, wie
printf("%s\n", s)
zuputs(s)
(wobei der puts-Aufruf aber natürlich nicht geinlined wird) und ähnliches.Ja gut, dann verstehe ich aber deinen Einwand nicht. Dass solche Sachen optimiert werden, wo der Compiler mit sehr hoher Wahrscheinlichkeit einen statischen Wert hinsetzen kann, ist mir schon vorher klar gewesen (siehe bereits erwähnte Compilerwarnungen - hier habe ich bereits öfter den "optimierten" Quellcode noch einmal angesehen, um zu prüfen, was da jetzt eigentlich generiert wurde und wo die Warnung generiert wurde). Aber solche Sachen packt man nun auch wirklich nicht in eine Funktion, und es geht hier ja um Funktionen, die verdeckt werden sollen, nicht um Bruchstücke im Code einer Funktion, wie es bei Inlines der Fall ist.
-
dachschaden schrieb:
Aber solche Sachen packt man nun auch wirklich nicht in eine Funktion, und es geht hier ja um Funktionen, die verdeckt werden sollen, nicht um Bruchstücke im Code einer Funktion, wie es bei Inlines der Fall ist.
Noch einmal in einfachen Worten: Der TE will irgendwelche Funktionen aus der Standardbibliothek ersetzen. Die Implementierung kann, darf und wird jedoch bereits bei recht niedrigem Optimierunglevel Funktionsaufrufe aus der Standardbibliothek:
a) ganz normal inlinen
oder
b) durch ganz was anderes ersetzen, so lange es nur das gleiche tutIn beiden Fällen funktioniert ein Eingriff auf Linkerebene nicht mehr wie gewollt, daher muss man dies verhindern.
Irgendwie denke ich, dass ich dein
dachschaden schrieb:
Sollte ein Compiler nicht eh (außer bei abnorm hohem Optimierungslevel - bei dem ich schon die eine oder andere Warnung für vom Compiler generiertem Code bekommen habe :D) nicht eh immer alles in eine eigene Funktion packen, wenn diese nicht in irgendeiner Art und Weise als inline deklariert wurde?
falsch verstanden habe, denn meiner Meinung nach macht dein letzter Beitrag wenig Sinn im Kontext. Daher stimmt vermutlich der Kontext nicht. Was genau meinst du mit "alles in eine eigene Funktion packen"?
-
Singender Holzkübel schrieb:
Würde mich aber interessieren, wofür du das brauchst.
Auf ARM Prozessoren scheint memcpy() etwas restriktiver gehandhabt zu werden. Man kann da wohl nicht einfach über Array-Grenzen hinwegschreiben.
char buf[size]; memcpy( &buf[offset], src, 4);
Da im Bsp. 4 Byte größer als das ein-Byte Array-Feld sind, haut ARM einen Error.
-
SeppJ schrieb:
Irgendwie denke ich, dass ich [deinen Beitrag] falsch verstanden habe, denn meiner Meinung nach macht dein letzter Beitrag wenig Sinn im Kontext. Daher stimmt vermutlich der Kontext nicht. Was genau meinst du mit "alles in eine eigene Funktion packen"?
Ach, verdammt. Da hatte ich einen Denkfehler. LD_PRELOAD funktioniert meines Wissens nur bei Symbolen, die über dynamische Bibliotheken nachgeladen werden. Dummer Hirnfurz, das.
Es ging mir darum: wenn ich TUs kompiliere und zusammenlinke, wer garantiert mir, dass sich die Symbole - sprich die Funktionen, deren DEFINITIONEN in den Objektdateien sind - nicht vom Compiler optimiert werden?
Ich hatte vor einiger Zeit hier nachgefragt, wie man eine dezimale Zahl schnell in einen String schreibt, und wollte dazu die Länge der Zahl in Basis 10 wissen. Als Tipp wurde die Logarithmusfunktion angeben, und die war auch sehr schnell, irgendwas mit 30 Cycles. Aber als ich dann die Berechnung in eine Funktion packte, wollte der Linker die Math-Lib mitdazuhaben, die ich vorher nicht brauchte (weil der Compiler den Call vonlog2
bereits wegoptimiert hatte). Mit der Bereichnung der Funktion war die Funktion aber dann da und hat 30.000 Cycles gekostet. Der Compiler hätte aber bei ausreichend hoher Optimierungsstufe sagen können, dass er das Ergebnis aller Calls schon mal im Voraus berechnet, die Werte einfügt, und die Funktion komplett rausnimmmt, weil die nur unnötig Ausführungszeit verbraucht. Wenn man dann versucht hätte, mit LD_PRELOAD die Funktion zu ersetzen, wäre nichts bei rumgekommen, weil die Funktion bereits komplett geinlined wurde und nicht mehr gefunden werden kann.Natürlich ergibt das keinen Sinn, wenn man von statischem Code wie in Objektdateien oder statischen Bibliotheken ausgeht, LD_PRELOAD funzt wie gesagt bei Funktionen in dynamischen Objekten. In diesem Fall ist das Executable ja bereits mit allen Funktionen bekannt gemacht worden, die dynamisch nachgeladen werden müssen - die also auch von den dynamischen Objekten exportiert werden müsen.
Sorry.
Wie gesagt, kurzzeitiger Hirnfurz.
-
olpo schrieb:
Auf ARM Prozessoren scheint memcpy() etwas restriktiver gehandhabt zu werden. Man kann da wohl nicht einfach über Array-Grenzen hinwegschreiben.
char buf[size]; memcpy( &buf[offset], src, 4);
Da im Bsp. 4 Byte größer als das ein-Byte Array-Feld sind, haut ARM einen Error.
Ähhhhh ... habe ich gerade wieder einen Hirnfurz? Über die Bytegrenzen eines Arrays zu schreiben ist generell keine gute Idee, es sei denn, du bist dir GANZ sicher, dass nach dem Wert noch ein definiertes Feld kommt, dass dich davon abhält, in deine Stackdaten zu schreiben.
OK, ist vielleicht nur eine dumme Vermutung, ich habe keine Ahnung von ARM, aber kann es sein, dass hier kein Redzoning unterstützt wird? Bei Redzoning hast du noch 128 Bytes nach dem eigentlichen Ende des Stacks, die du Beschreiben kannst, da kann das abgefangen werden.
-
dachschaden schrieb:
Ähhhhh ... habe ich gerade wieder einen Hirnfurz? Über die Bytegrenzen eines Arrays zu schreiben ist generell keine gute Idee, es sei denn, du bist dir GANZ sicher, dass nach dem Wert noch ein definiertes Feld kommt, dass dich davon abhält, in deine Stackdaten zu schreiben.
Ja, ich finde das auch nicht schön.
Und das ist legacy code von IBM.
dachschaden schrieb:
OK, ist vielleicht nur eine dumme Vermutung, ich habe keine Ahnung von ARM, aber kann es sein, dass hier kein Redzoning unterstützt wird? Bei Redzoning hast du noch 128 Bytes nach dem eigentlichen Ende des Stacks, die du Beschreiben kannst, da kann das abgefangen werden.
Weiß ich nicht. Aber da ARM für eingebettete Systeme mit wenig Speicherplatz ist, vermute ich mal, dass das nicht standardmäßig eingefügt wird.
Egal, was haltet ihr von myMemcpy?
Irgendwas auszusetzen? Gefährliche Pointer-Sachen, oder alles richtig, schön und sauber?void myMemcpy(void *dest, const void *src, size_t n){ unsigned int i; uint8_t *destination = (uint8_t*) dest; uint8_t *source = (uint8_t*) src; for ( i=0; i<n; i++){ *(destination+i) = *(source+i); }
-
Erklär noch mal, warum du Standardfunktionen 'ver(schlimm)bessern' oder gar ersetzen willst.
-
Und siehst du hier eine Standardreferenzimplementierung.
Also, ich kann's verstehen. Zwar nicht so, wie olpo das macht (keine Vektorisierung und auch keine Anpassung an die CPU-Architektur), aber der Gedanke generell ist nicht dumm. Und es ist ja nicht so, als ob seine Funktion in einen neuen Standard einfließen wird.