Zajmuję się głównie programowaniem na urządzeniach z portem Linux, więc standardowa biblioteka C zapewnia wiele funkcji dzięki implementacji wywołań systemowych o znormalizowanym zachowaniu.
Jednak w przypadku samego metalu nie ma systemu operacyjnego. Czy istnieje standard związany z tym, w jaki sposób należy zaimplementować bibliotekę ac, czy też trzeba nauczyć się osobliwości implementacji biblioteki po przejściu na nową płytę, która zapewnia inny BSP?
Odpowiedzi:
Tak, jest to standard, po prostu biblioteki standardowej C . Funkcje biblioteczne nie wymagają „pełnego systemu operacyjnego” ani żadnego systemu operacyjnego, a istnieje wiele implementacji dostosowanych do kodu „bare metal”, prawdopodobnie Newlib jest najbardziej znany.
Biorąc za przykład Newlib, wymaga napisania małego podzbioru podstawowych funkcji, głównie sposobu obsługi plików i alokacji pamięci w systemie. Jeśli korzystasz ze wspólnej platformy docelowej, istnieje prawdopodobieństwo, że ktoś już wykonał tę pracę za Ciebie.
Jeśli używasz Linuksa (prawdopodobnie także OSX, a może nawet cygwin / msys?) I piszesz
man strlen
, powinien on mieć sekcję o nazwie coś podobnegoCONFORMING TO
, co wskazywałoby, że implementacja jest zgodna z określonym standardem. W ten sposób możesz dowiedzieć się, czy coś, czego używasz, jest funkcją standardową, czy też zależy od konkretnego systemu operacyjnego.źródło
stdlib
implementuje sięstdio
bez uzależnienia od systemu operacyjnego. jakfopen()
,fclose()
,fread()
,fwrite()
,putc()
igetc()
? i jakmalloc()
działa bez rozmowy z systemem operacyjnym?getchar
iputchar
które wiedzą o UART twojego sprzętu; następnie warstwy Newlibprintf
na nich. Plikowe operacje wejścia / wyjścia będą podobnie opierały się na kilku operacjach podstawowych.stdin
istdout
astderr
(który dbaputchar()
igetchar()
), który kieruje I / O z / do UART, jeśli platforma ma zapisu plików, jak przy użyciu lampy błyskowej, to trzeba napisać, że również dla kleju. i musisz mieć środki namalloc()
ifree()
. myślę, że jeśli rozwiążesz te problemy, możesz praktycznie uruchomić przenośne C we wbudowanym celu (nieargv
aniargc
).Po pierwsze, standard C definiuje coś, co nazywa się implementacją „wolnostojącą”, w przeciwieństwie do implementacji „hostowanej” (co jest znane większości z nas, pełen zakres funkcji C obsługiwanych przez podstawowy system operacyjny).
Implementacja „wolnostojąca” musi definiować tylko podzbiór nagłówków biblioteki C, a mianowicie te, które nie wymagają wsparcia, a nawet definicję funkcji (tylko
#define
s itypedef
s):<float.h>
<iso646.h>
<limits.h>
<stdalign.h>
<stdarg.h>
<stdbool.h>
<stddef.h>
<stdint.h>
<stdnoreturn.h>
Kiedy robisz następny krok w kierunku implementacji hostowanej, przekonasz się, że istnieje bardzo niewiele funkcji, które naprawdę muszą w jakikolwiek sposób interfejsować „system”, a resztę biblioteki można zaimplementować na podstawie tych „prymitywów” „. Wdrażając PDCLib , starałem się odizolować je w osobnym podkatalogu, aby ułatwić identyfikację podczas przenoszenia biblioteki lib na nową platformę (przykłady portu Linux w nawiasach):
getenv()
(extern char * * environ
)system()
(fork()
/execve()
/wait()
)malloc()
ifree()
(brk()
/sbrk()
)_Exit()
(_exit()
)time()
(jeszcze niezaimplementowane)I dla
<stdio.h>
(prawdopodobnie najbardziej „zaangażowanego w system operacyjny” z nagłówków C99):open()
)close()
)unlink()
)link()
/unlink()
)write()
)read()
)lseek()
)Niektóre szczegóły biblioteki są opcjonalne, a standard oferuje jedynie ich implementację w standardowy sposób, ale nie czyni takiej implementacji wymaganiem.
time()
Funkcja może legalnie prostu wrócić(time_t)-1
, jeśli nie ma mechanika czas utrzymywania są dostępne.Opisane procedury obsługi sygnałów
<signal.h>
nie muszą być wywoływane przez nic innego niż wezwanie doraise()
, nie ma wymogu, aby system faktycznie wysyłał coś podobnegoSIGSEGV
do aplikacji.Nagłówek C11
<threads.h>
, który (z oczywistych powodów) jest bardzo zależny od systemu operacyjnego, nie musi być wcale dostarczany, jeśli implementacja definiuje__STDC_NO_THREADS__
...Jest więcej przykładów, ale nie mam ich teraz pod ręką.
Resztę biblioteki można zaimplementować bez pomocy środowiska. (*)
(*) Zastrzeżenie: Implementacja PDCLib nie jest jeszcze ukończona, więc mogłem przeoczyć coś lub dwa. ;-)
źródło
Standard C jest faktycznie zdefiniowany oddzielnie od środowiska operacyjnego. Nie zakłada się obecności systemu operacyjnego hosta, a części zależne od hosta są zdefiniowane jako takie.
Oznacza to, że C Standard jest już całkiem gołym metalem.
Oczywiście te części językowe, które tak bardzo kochamy, biblioteki, są często miejscem, w którym główny język popycha konkretne rzeczy. Stąd typowe dla kompilatora krzyżowego „xxx-lib” znalezione dla wielu narzędzi platformy typu bare metal.
źródło
Przykład minimalnego uruchamiania Newlib
Tutaj podaję wysoce zautomatyzowany i udokumentowany przykład pokazujący newlib w działaniu w QEMU .
Dzięki newlib możesz zaimplementować własne wywołania systemowe dla swojej platformy baremetal.
Na przykład w powyższym przykładzie mamy przykładowy program
exit.c
:a w osobnym pliku C
common.c
implementujemy semihostingexit
z ARM :Inne typowe wywołania systemowe, które zaimplementujesz, to:
write
wyprowadzać wyniki do hosta. Można to zrobić za pomocą:brk
dlamalloc
.Łatwo na boso, ponieważ nie musimy przejmować się stronicowaniem!
TODO Zastanawiam się, czy realistyczne jest osiągnięcie wyprzedzającego wykonania syscalls planowania bez wchodzenia w pełną wersję RTOS, taką jak Zephyr lub FreeRTOS .
Fajną rzeczą w Newlib jest to, że implementuje on wszystkie rzeczy niezwiązane z systemem operacyjnym, takie jak
string.h
dla ciebie, i pozwala implementować tylko pośredniczące systemu operacyjnego.Nie musisz też implementować wszystkich kodów pośredniczących, ale tylko tych, których będziesz potrzebować. Na przykład, jeśli twój program potrzebuje tylko
exit
, nie musisz podawaćprint
.Drzewo źródeł Newlib ma już pewne implementacje, w tym implementację półhostingu ARM pod
newlib/libc/sys/arm
, ale w większości musisz implementować własną. Stanowi jednak solidną podstawę do zadania.Najprostszym sposobem na skonfigurowanie Newlib jest zbudowanie własnego kompilatora za pomocą crosstool-NG, wystarczy powiedzieć, że chcesz używać Newlib jako biblioteki C. Moja konfiguracja obsługuje to automatycznie za pomocą tego skryptu , który korzysta z konfiguracji newlib obecnych w
crosstool_ng_config
.Myślę, że C ++ również będzie działał, ale TODO to przetestuje.
źródło
Kiedy używasz go od razu, odkrywasz pewne niezaimplementowane zależności i musisz sobie z nimi poradzić. Wszystkie te zależności dotyczą dostosowania elementów wewnętrznych do osobowości twojego systemu. Na przykład, gdy próbowałem użyć sprintf (), który korzysta z malloc () wewnątrz. Malloc ma symbol funkcji „t_sbrk” jako kod przechwytujący, który musi zostać zaimplementowany przez użytkownika w celu wymuszenia konsol sprzętowych. Tutaj mogę go zaimplementować lub stworzyć własny malloc (), jeśli uważam, że mógłbym zrobić lepszy dla wbudowanego sprzętu, głównie do innych zastosowań, nie tylko sprintf.
źródło