Hallo zusammen,
ich hab mal kurz eine Frage zum Verständnis.
Angenommen ich habe einen µC ohne Betriebssystem und entwickle mit GCC.
Nun kann ich ja problemlos libc-Funktionen wie sprintf() verwenden.
Was ist denn aber mit libc-Funktionen, die eigentlich einen SystemCall
ausführen würden, also z.B. fopen() oder fread()? Es gibt ja kein
Betriebssystem, das den SystemCall entgegennehmen könnte.
Wie entscheidet der GCC, was er mit diesen Aufrufen machen soll?
Torsten Robitzki schrieb:> Ich würde erwarten, dass der Linker Dir einfach ein "undefined symbol"> präsentiert.
Nein, läßt sich einwandfrei builden. Es passiert nur anscheinend nichts.
Jens Langecker schrieb:> Was ist denn aber mit libc-Funktionen, die eigentlich einen SystemCall> ausführen würden, also z.B. fopen() oder fread()?
Nein, fopen() und fread() sind ebenfalls keine Syscalls, sondern
Bibliotheksfunktionen, genau wie printf().
Was darunter benutzt wird, hängt dann von der jeweiligen Implementierung
der Bibliothek ab. Bei der Newlib (wie sie beim ARM-GCC gern benutzt
wird) sind das Posix-typische Syscalls (open(), close(), read(),
write()), die du selbst beisteuern musst, oder für die es ggf. auch
Dummies in der Lib gibt. Bei der avr-libc gibt es fdevopen() als
Pendant zum klassischen open(), oder auch statische Varianten davon,
bei denen man einen Stream zur Compilezeit vorkonfiguriert. Die
Funktionen zum Lesen und Schreiben eines Zeichens muss man natürlich
auch da selbst liefern.
Jens Langecker schrieb:> Nein, läßt sich einwandfrei builden. Es passiert nur anscheinend nichts.
Das deutet daraufhin, dass die Bibliothek vorgefertigte Dummies
enthält.
ARM + Newlib?
Jörg Wunsch schrieb:> Jens Langecker schrieb:>> Nein, läßt sich einwandfrei builden. Es passiert nur anscheinend nichts.>> Das deutet daraufhin, dass die Bibliothek vorgefertigte Dummies> enthält.>> ARM + Newlib?
Korrekt. Hab mich inzwischen durch die Doku gewühlt und die Stubs
gefunden.
Danke!
Jörg Wunsch schrieb:> Bei der Newlib (wie sie beim ARM-GCC gern benutzt wird) sind das> Posix-typische Syscalls (open(), close(), read(), write()),> die du selbst beisteuern musst, oder für die es ggf. auch> Dummies in der Lib gibt. Bei der avr-libc gibt es fdevopen() als> Pendant zum klassischen open(),
Vor einiger Zeit wollte ich open etc. auf Syscalls abbilden, quasi als
Backend für fopen, fprintf, etc. Ich hätte gedacht dafür gäbe es weak
Stubs in der avr-libc, die ich dann auf Syscalls hätte abbilden können.
Aber solche Stubs scheint es in der avr-libc nicht zu geben...
Johann L. schrieb:> Aber solche Stubs scheint es in der avr-libc nicht zu geben...
Nee, die tickt ein bisschen anders.
Als ich das stdio dort geschrieben habe, wollte ich deutlich
sparsamer mit den Ressourcen umgehen, als das newlib & Co. machen.
Selbst mit fdevopen() wurde ich noch ausreichend kritisiert (und
habe dann die statischen Varianten nachgeliefert), da es in diesem
Umfeld genügend „malloc() ist absolut böse“-Fetischisten gibt.
Das, was man schon zu PDP-11-Zeiten in stdio gepuffert hat (in
hässlichsten Makros dazumals), ist eben für einen ATmega8 schon mal
deutlich zu viel SRAM-Bedarf. Pro Stream eine Funktion zum Lesen
eines Zeichens und eine zum Schreiben ist gerade so OK.
Jörg Wunsch schrieb:> Pro Stream eine Funktion zum Lesen> eines Zeichens und eine zum Schreiben ist gerade so OK.
Aus aktuellem Anlass interessiert mich das Thema sehr.
Ich dachte mehr bräucht ein Stream auch nicht? Also eine getc() und eine
putc(). Inwiefern wird da in der stdio noch gepuffert, bzw. wo würde das
malloc() ins Spiel kommen?
Gruß,
Ben
Kaj G. schrieb:> Beitrag "ARM - Probleme mit sprintf (Linkerfehler)"
Nachdem ich diesen Thread gelesen habe, hab ich aber noch eine Frage:
Ich benutze Atollic TrueSUTDIO (GCC 4.8.3) für einen STM32 und habe kein
Betriebssystem.
Ich mache exzessiven Gebrauch von vsnprintf() und das funktioniert
problemlos.
Wenn ich es richtig verstehe, verwendet vsnprintf() malloc() bzw.
sbrk().
sbrk() habe ich nicht selbst beigesteuert.
Wer könnte denn in meinem Setup so freundlich sein, mir sbrk() zur
Verfügung zu stellen?
Jens Langecker schrieb:> Wenn ich es richtig verstehe, verwendet vsnprintf() malloc() bzw.> sbrk().
Warum sollte es?
die 's' Versionen der printf Familie schreiben in einen Buffer, den der
Aufrufer zur Verfügung stellen muss. Da gibt es keinen Bedarf an
dynamisch allokierten Speicher bzw. das ist so wenig, dass er mit
funktionslokalen Variablen abzudecken ist. Ein long hat eine
überschaubare und im Vorfeld bekannte maximale Textrepräsentierung.
Dafür den Speicher dynamisch mittels malloc zu allokieren, wäre völliger
Overkill.
Ben schrieb:> Ich dachte mehr bräucht ein Stream auch nicht?
Braucht er auch nicht.
> Also eine getc() und eine> putc().
Yep, als Methoden, die im Stream-Objekt hinterlegt werden.
> Inwiefern wird da in der stdio noch gepuffert,
Gar nicht.
> bzw. wo würde das> malloc() ins Spiel kommen?
Nur beim fdevopen(), um den Platz für das Stream-Objekt selbst zu
bekommen. Das ist überhaupt nicht tragisch, wenn an diesen Objekten
nie mehr was geändert wird, dann fragmentiert davon auch kein Speicher
und nichts, das malloc() beißt auch nicht den Programmierer in den
Zeh. :-)) Der einzige wirkliche Nachteil ist, dass man sich natürlich
zusätzlichen Code (für malloc() selbst) mit auflädt.
Daher habe ich dann als Alternativen FDEV_SETUP_STREAM() bzw.
fdev_setup_stream() nachgereicht, bei denen der Nutzer den Speicher
selbst bereitstellen muss.
Jens Langecker schrieb:> Wenn ich es richtig verstehe, verwendet vsnprintf() malloc() bzw.> sbrk().
In der Newlib? Nur für Gleitkommaoperationen, da wird ein
Zwischenspeicher alloziert.
Da haben sie noch einen bösen Bug drin, sind wir erst vor paar Tagen
drüber gestolpert (binutils bug #18212), da wird das Ergebnis eines
malloc() ungeprüft weiterbenutzt. Gab malloc() einen Nullzeiger
zurück, so versuchen sie anschließend, auf Adresse 0 zu schreiben
(was uns in unserem Falle einen HardFault eingebrockt hat).
Ben schrieb:> Ich dachte mehr bräucht ein Stream auch nicht? Also eine getc() und eine> putc(). Inwiefern wird da in der stdio noch gepuffert, bzw. wo würde das> malloc() ins Spiel kommen?
Zb brauchst du für jeden fopen eine FILE Struktur. Will dein
Anwendungsprogramm gleichzeitig 20 Files öffnen, müssen die irgendwo
herkommen.
Du hast die Wahl zwischen statischer Allokierung einer entsprechenden
Anzahl x im Vorfeld (mit entsprechendem Speicherplatzverbrauch) oder
einer dynamischen Allokierung. In dem einen Fall ist nach x Files damit
automatisch Schluss mit lustig bzw. je nach x sind es zu wenige oder du
investierst zuviel Speicher. Oder eben im anderen Fall musst du die
dynamische Allokierung bemühen.
Jörg Wunsch schrieb:> zu PDP-11-Zeiten
Da war ich noch flüssig ;o)
> für einen ATmega8 schon mal deutlich zu viel SRAM-Bedarf.> Pro Stream eine Funktion zum Lesen eines Zeichens und eine zum> Schreiben ist gerade so OK.
War in einem Simulator-Umgebung, da wäre es ganz nett wenn die
Standardfunktionen verfügbar werden, etwa in der avr-gcc Testsuite. Da
kann man ja nicht einfach fdevopen verwenden.
Vor einiger Zeit hatte ich den AVR-Simulator von magischen SFRs auf
Syscalls umgestellt. Im Gegensatz zu magischen SFRs haben Syscalls
keinen Overhead für den Simulator, d.h. der Simulator könnte so
Scherze bieten wie vom avr-Programm auf das Host-Dateisystem zuzugreifen
ohne die Simulation zu verlangsamen :-)
Weils grad thematisch hier passt:
Wenn ich so wie im Tutorial hier beschrieben stdout auf meine UART
Funktionen umleite dann kann ich per printf/scanf Daten lesen und
schreiben, was oft komfortabler ist als die typischen uart_putc() oder
uartputs().
Was aber wenn ich Binärdaten lesen/schreiben will?
Also z.B. ein UART Protokoll parsen will dass nicht nuur ASCII enthält?
Welche Funktionen würd ich da benutzen?
Ich tippe mal auf fread und fwrite, denen ich dann stdin und stdout
mit-übergebe, richtig?
Was mach ich mit dem __size-Parameter? Einfach immer auf 1 setzen?
Grüße,
Haro
Haro schrieb:> Ich tippe mal auf fread und fwrite, denen ich dann stdin und stdout> mit-übergebe, richtig?> Was mach ich mit dem __size-Parameter? Einfach immer auf 1 setzen?
Auf die Größe des zu lesenden Elements.