Ich entwickle hauptsächlich auf Geräten, die Linux portiert haben, sodass die Standard-C-Bibliothek viele Funktionen bietet, indem sie Systemaufrufe implementiert, die ein standardisiertes Verhalten aufweisen.
Für Bare Metal gibt es jedoch kein zugrunde liegendes Betriebssystem. Gibt es einen Standard bezüglich der Implementierung einer Bibliothek oder müssen Sie die Besonderheiten einer Bibliotheksimplementierung neu lernen, wenn Sie auf eine neue Karte wechseln, die ein anderes BSP bietet?
Antworten:
Ja, es gibt einen Standard, einfach die C-Standardbibliothek . Die Bibliotheksfunktionen erfordern kein "ausgewachsenes" Betriebssystem oder ein Betriebssystem überhaupt, und es gibt eine Reihe von Implementierungen, die auf "Bare-Metal" -Code zugeschnitten sind, wobei Newlib vielleicht das bekannteste ist.
Am Beispiel von Newlib müssen Sie eine kleine Untergruppe von Kernfunktionen schreiben, hauptsächlich wie Dateien und Speicherzuordnung in Ihrem System gehandhabt werden. Wenn Sie eine gemeinsame Zielplattform verwenden, hat wahrscheinlich bereits jemand diese Aufgabe für Sie erledigt.
Wenn Sie Linux verwenden (wahrscheinlich auch OSX und vielleicht sogar cygwin / msys?) Und tippen
man strlen
, sollte es einen Abschnitt mit der Bezeichnung "Etwas" gebenCONFORMING TO
, der Ihnen sagt, dass die Implementierung einem bestimmten Standard entspricht. Auf diese Weise können Sie herausfinden, ob etwas, das Sie verwendet haben, eine Standardfunktion ist oder ob es von einem bestimmten Betriebssystem abhängt.quelle
stdlib
Gerät funktioniert ,stdio
ohne vom Betriebssystem abhängig zu sein. wiefopen()
,fclose()
,fread()
,fwrite()
,putc()
undgetc()
? und wie funktioniert esmalloc()
, ohne mit dem Betriebssystem zu sprechen?getchar
undputchar
welche wissen über den UART Ihrer Hardware Bescheid; dann schichtet Newlib darüberprintf
. Die Datei-E / A stützt sich ebenfalls auf einige Grundelemente.stdin
undstdout
undstderr
(das sich umputchar()
und kümmertgetchar()
), das I / O von / zu einem UART leitet, müssen Sie auch dafür Klebstoff schreiben, wenn Ihre Plattform über Dateispeicher verfügt, z. B. mit einem Flash. und Sie müssen die Mittel zumalloc()
und habenfree()
. Ich denke, wenn Sie sich um diese Probleme kümmern, können Sie Portable C in Ihrem eingebetteten Ziel ausführen (wederargv
nochargc
).Zunächst definiert der C-Standard etwas, das als "freistehende" Implementierung bezeichnet wird, im Gegensatz zu einer "gehosteten" Implementierung (mit der die meisten von uns vertraut sind, dh mit dem vollen Umfang der C-Funktionen, die vom zugrunde liegenden Betriebssystem unterstützt werden).
Eine "freistehende" Implementierung muss nur eine Teilmenge der C-Bibliotheks-Header definieren, nämlich diejenigen, die keine Unterstützung benötigen, oder sogar die Definition von Funktionen (sie tun lediglich
#define
s undtypedef
s):<float.h>
<iso646.h>
<limits.h>
<stdalign.h>
<stdarg.h>
<stdbool.h>
<stddef.h>
<stdint.h>
<stdnoreturn.h>
Wenn Sie den nächsten Schritt in Richtung einer gehosteten Implementierung machen, werden Sie feststellen, dass es nur sehr wenige Funktionen gibt, die wirklich "das System" in irgendeiner Weise verbinden müssen, wobei der Rest der Bibliothek über diesen "Grundelementen" implementiert werden kann ". Bei der Implementierung der PDCLib habe ich mich bemüht, sie in einem separaten Unterverzeichnis zu isolieren, um sie beim Portieren der lib auf eine neue Plattform leichter identifizieren zu können (Beispiele für den Linux-Port in Klammern):
getenv()
(extern char * * environ
)system()
(fork()
/execve()
/wait()
)malloc()
undfree()
(brk()
/sbrk()
)_Exit()
(_exit()
)time()
(noch nicht implementiert)Und für
<stdio.h>
(wohl die am meisten "am Betriebssystem beteiligten" der C99-Header):open()
)close()
)unlink()
)link()
/unlink()
)write()
)read()
)lseek()
)Bestimmte Details der Bibliothek sind fakultativ, da der Standard lediglich eine standardmäßige Implementierung anbietet , eine solche Implementierung jedoch nicht erforderlich macht.
Die
time()
Funktion kann legal zurückkehren,(time_t)-1
wenn keine Zeitmessmechanik verfügbar ist.Die für beschriebenen Signalhandler
<signal.h>
müssen nur durch einen Aufruf von aufgerufen werden.raise()
Es ist nicht erforderlich, dass das System tatsächlich so etwas wie an die Anwendung sendetSIGSEGV
.Der C11-Header
<threads.h>
, der (aus offensichtlichen Gründen) stark vom Betriebssystem abhängig ist, muss überhaupt nicht bereitgestellt werden, wenn die Implementierung Folgendes definiert__STDC_NO_THREADS__
:Es gibt weitere Beispiele, aber ich habe sie momentan nicht zur Hand.
Der Rest der Bibliothek kann ohne Hilfe der Umgebung implementiert werden. (*)
(*) Einschränkung: Die PDCLib-Implementierung ist noch nicht abgeschlossen, daher habe ich möglicherweise ein oder zwei Dinge übersehen. ;-)
quelle
Standard C wird tatsächlich unabhängig von der Betriebsumgebung definiert. Es wird keine Annahme getroffen, dass ein Host-Betriebssystem vorhanden ist, und diejenigen Teile, die vom Host abhängig sind, werden als solche definiert.
Das heißt, der C-Standard ist schon ziemlich blank.
Natürlich sind diese von uns so geliebten Sprachteile, die Bibliotheken, oft der Ort, an dem die Kernsprache das Hosting bestimmter Inhalte vorantreibt. Daher das typische Cross-Compiler-Zeug "xxx-lib", das für viele Bare-Metal-Plattform-Tools zu finden ist.
quelle
Newlib minimal lauffähiges Beispiel
Hier stelle ich ein hochautomatisiertes und dokumentiertes Beispiel zur Verfügung, das Newlib in Aktion in QEMU zeigt .
Mit newlib implementieren Sie Ihre eigenen Systemaufrufe für Ihre Baremetal-Plattform.
Im obigen Beispiel haben wir zum Beispiel ein Beispielprogramm
exit.c
:und in einer separaten C-Datei
common.c
implementieren wir dasexit
mit ARM Semihosting :Die anderen typischen Systemaufrufe, die Sie implementieren, sind:
write
Ergebnisse an den Host ausgeben. Dies kann entweder mit:brk
fürmalloc
.Schont das Baremetall, da wir uns nicht um Paging kümmern müssen!
TODO Ich frage mich, ob es realistisch ist, eine vorbeugende Planung der Ausführung von Systemaufrufen zu erreichen, ohne auf ein vollwertiges RTOS wie Zephyr oder FreeRTOS umzusteigen .
Das Coole an Newlib ist, dass es alle nicht-OS-spezifischen Dinge
string.h
implementiert, die Sie mögen , und dass Sie nur die OS-Stubs implementieren können.Außerdem müssen Sie nicht alle Stubs implementieren, sondern nur die, die Sie benötigen. ZB wenn Ihr Programm nur benötigt
exit
, dann müssen Sie keinprint
.Der Newlib-Quelltextbaum enthält bereits einige Implementierungen, einschließlich einer ARM-Semihosting-Implementierung
newlib/libc/sys/arm
, die Sie jedoch größtenteils selbst implementieren müssen. Es bietet jedoch eine solide Basis für die Aufgabe.Die einfachste Möglichkeit, Newlib einzurichten, besteht darin, einen eigenen Compiler mit Crosstool-NG zu erstellen. Sie müssen lediglich angeben, dass Sie Newlib als C-Bibliothek verwenden möchten. Mein Setup erledigt das automatisch für Sie mit diesem Skript , das die newlib configs verwendet, die bei vorhanden sind
crosstool_ng_config
.Ich denke, C ++ wird auch funktionieren, aber TODO testet es.
quelle
Wenn Sie es baremetal benutzen, entdecken Sie einige nicht implementierte Abhängigkeiten und müssen mit ihnen umgehen. Bei all diesen Abhängigkeiten geht es darum, die Interna entsprechend der Persönlichkeit Ihres Systems abzustimmen. Zum Beispiel, als ich versucht habe, sprintf () zu verwenden, das malloc () verwendet. Malloc hat das Funktionssymbol "t_sbrk" als Hook-In-Code, der vom Benutzer implementiert werden muss, um die Hardware-Einschränkungen durchzusetzen. Hier kann ich es implementieren oder mein eigenes malloc () erstellen, wenn ich glaube, dass ich ein besseres für die eingebettete Hardware machen kann, hauptsächlich für andere Zwecke, nicht nur für sprintf.
quelle