Principalmente estoy haciendo desarrollo en dispositivos que han portado Linux, por lo que la biblioteca C estándar proporciona mucha funcionalidad a través de la implementación de llamadas al sistema que tienen un comportamiento estandarizado.
Sin embargo, para el metal desnudo, no hay un SO subyacente. ¿Existe un estándar relacionado con la forma en que debe implementarse la biblioteca de CA o tiene que volver a aprender la peculiaridad de las implementaciones de una biblioteca cuando cambia a una nueva placa que proporciona un BSP diferente?
Respuestas:
Sí, hay una norma, sólo la biblioteca estándar C . Las funciones de la biblioteca no requieren un sistema operativo "completo", o cualquier sistema operativo en absoluto, y hay una serie de implementaciones adaptadas al código "bare metal", tal vez Newlib sea el más conocido.
Tomando Newlib como ejemplo, requiere que escriba un pequeño subconjunto de funciones básicas, principalmente cómo se manejan los archivos y la asignación de memoria en su sistema. Si está utilizando una plataforma de destino común, es probable que alguien ya haya hecho este trabajo por usted.
Si está utilizando Linux (¿probablemente también OSX y tal vez incluso cygwin / msys?) Y escriba
man strlen
, debería tener una sección llamada algo asíCONFORMING TO
, que le diría que la implementación se ajusta a un estándar específico. De esta manera, puede averiguar si algo que ha estado usando es una función estándar o si depende de un sistema operativo específico.fuente
stdlib
implementastdio
sin depender del sistema operativo. comofopen()
,fclose()
,fread()
,fwrite()
,putc()
ygetc()
? ¿Y cómomalloc()
funciona sin hablar con el sistema operativo?getchar
yputchar
lo que saben acerca de su hardware UART; luego capas Newlibprintf
encima de estas. La E / S de archivo también se basará en algunas primitivas.stdin
ystdout
ystderr
(que se encarga deputchar()
ygetchar()
) que dirige la E / S desde / hacia un UART, si su plataforma tiene almacenamiento de archivos, como con un flash, entonces también debe escribir pegamento para eso. y tienes que tener los medios paramalloc()
yfree()
. Creo que si se ocupa de esos problemas, puede ejecutar C portátil en su objetivo incrustado (noargv
niargc
).En primer lugar, el estándar C define algo llamado implementación "independiente", en oposición a una implementación "alojada" (que es con lo que la mayoría de nosotros estamos familiarizados, la gama completa de funciones C compatibles con el SO subyacente).
Un "independiente" necesidades de implementación para definir sólo un subconjunto de las cabeceras de la biblioteca C, es decir, aquellos que no requieren soporte, o incluso la definición de funciones (que simplemente hacen
#define
s ytypedef
S):<float.h>
<iso646.h>
<limits.h>
<stdalign.h>
<stdarg.h>
<stdbool.h>
<stddef.h>
<stdint.h>
<stdnoreturn.h>
Cuando esté dando el siguiente paso hacia una implementación alojada, encontrará que solo hay muy pocas funciones que realmente necesiten interactuar con "el sistema" de alguna manera, con el resto de la biblioteca implementable sobre esas "primitivas". ". Al implementar el PDCLib , hice un esfuerzo para aislarlos en un subdirectorio separado para una fácil identificación al portar la biblioteca a una nueva plataforma (ejemplos para el puerto Linux entre paréntesis):
getenv()
(extern char * * environ
)system()
(fork()
/execve()
/wait()
)malloc()
yfree()
(brk()
/sbrk()
)_Exit()
(_exit()
)time()
(aún sin implementar)Y para
<stdio.h>
(posiblemente el más "OS-OS" de los encabezados C99):open()
)close()
)unlink()
)link()
/unlink()
)write()
)read()
)lseek()
)Ciertos detalles de la biblioteca son opcionales, con el estándar simplemente ofreciéndolos para que se implementen de manera estándar, pero no hacen que dicha implementación sea un requisito.
La
time()
función puede regresar legalmente(time_t)-1
si no hay mecanismos de cronometraje disponibles.Los manejadores de señal descritos
<signal.h>
no necesitan ser invocados por otra cosa que no sea una llamadaraise()
, no hay requisito de que el sistema realmente envíe algo parecidoSIGSEGV
a la aplicación.No es necesario proporcionar el encabezado C11
<threads.h>
, que (por razones obvias) depende mucho del sistema operativo, si la implementación define__STDC_NO_THREADS__
...Hay más ejemplos, pero no los tengo a la mano en este momento.
El resto de la biblioteca se puede implementar sin ninguna ayuda del entorno. (*)
(*) Advertencia: la implementación de PDCLib aún no está completa, por lo que podría haber pasado por alto una o dos cosas. ;-)
fuente
El estándar C en realidad se define separado del entorno operativo. No se asume que un SO host esté presente, y las partes que dependen del host se definen como tales.
Es decir, el C Standard ya es bastante simple.
Por supuesto, las partes del lenguaje que tanto amamos, las bibliotecas, son a menudo donde el lenguaje central empuja ese material específico del host. Por lo tanto, el típico compilador cruzado "xxx-lib" encontrado para muchas herramientas de plataforma de metal desnudo.
fuente
Ejemplo ejecutable mínimo de Newlib
Aquí proporciono un ejemplo altamente automatizado y documentado que muestra newlib en acción en QEMU .
Con newlib, implementa sus propias llamadas al sistema para su plataforma baremetal.
Por ejemplo, en el ejemplo anterior, tenemos un programa de ejemplo
exit.c
:y en un archivo C separado
common.c
, implementamosexit
con semihosting ARM :Los otros syscalls típicos que implementará son:
write
para dar resultados al host. Esto se puede hacer con:brk
paramalloc
.¡Fácil en metal desnudo, ya que no tenemos que preocuparnos por la paginación!
TODO Me pregunto si es realista alcanzar la ejecución preventiva de syscalls de programación sin entrar en un RTOS completo como Zephyr o FreeRTOS .
Lo bueno de Newlib es que implementa todas las cosas que no son específicas del sistema operativo, como
string.h
usted, y le permite implementar solo los apéndices del sistema operativo.Además, no tiene que implementar todos los apéndices, sino solo los que necesitará. Por ejemplo, si su programa solo lo necesita
exit
, entonces no tiene que proporcionar aprint
.El árbol fuente de Newlib ya tiene algunas implementaciones, incluida una implementación de semihosting ARM
newlib/libc/sys/arm
, pero en su mayor parte debe implementar la suya propia. Sin embargo, proporciona una base sólida para la tarea.La forma más fácil de configurar Newlib es compilando su propio compilador con crosstool-NG, solo tiene que decirle que desea usar Newlib como la biblioteca C. Mi configuración lo maneja automáticamente con este script , que usa las configuraciones newlib presentes en
crosstool_ng_config
.Creo que C ++ también funcionará, pero TODO lo prueba.
fuente
Cuando lo usa baremetal, descubre algunas dependencias no implementadas y tiene que manejarlas. Todas estas dependencias se tratan de ajustar los elementos internos de acuerdo con la personalidad de su sistema. Por ejemplo, cuando intenté usar sprintf () que usa malloc () dentro. Malloc tiene el símbolo de función "t_sbrk" como un código de enlace, que debe ser implementado por el usuario para aplicar las restricciones de hardware. Aquí puedo implementarlo o crear mi propio malloc () si creo que podría hacer uno mejor para el hardware incorporado, principalmente para otros usos, no solo sprintf.
fuente