bibliotecas estándar en metal desnudo

21

La mayoría de las veces realizo desarrollos en dispositivos que han portado Linux, por lo que la biblioteca estándar de C ofrece muchas funcionalidades 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 algún estándar relacionado con la forma en que se debe implementar una biblioteca c o tiene que volver a aprender la peculiaridad de las implementaciones de una biblioteca cuando se cambia a una nueva placa que proporciona un BSP diferente?

    

5 respuestas

19

Sí, hay un estándar, simplemente la biblioteca estándar de C . Las funciones de la biblioteca no requieren un sistema operativo "completo", o ningún sistema operativo en absoluto, y hay una serie de implementaciones que se adaptan al código "simple", Newlib Quizás sea el más conocido.

Tomando Newlib como ejemplo, requiere que escriba un pequeño subconjunto de funciones básicas, principalmente sobre 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á usando linux (probablemente también OSX e incluso cygwin / msys?) y escriba man strlen , debería tener una sección llamada algo así como CONFORMING TO , lo que le diría que la implementación se ajusta a un determinado estándar. De esta manera, puedes averiguar si algo que has estado usando es una función estándar o si depende de un sistema operativo específico.

    
respondido por el pipe
8
  

¿Existe algún estándar relacionado con la forma en que se debe implementar una biblioteca c o tiene que volver a aprender la peculiaridad de las implementaciones de una biblioteca cuando se cambia a una nueva placa que proporciona un BSP diferente?

En primer lugar, el estándar de C define algo que se llama una implementación "independiente", a diferencia de una implementación "alojada" (que es con lo que la mayoría de nosotros estamos familiarizados, la gama completa de funciones de C admitidas por el sistema operativo subyacente).

Una implementación "independiente" necesita definir solo un subconjunto de los encabezados de la biblioteca C, es decir, aquellos que no requieren soporte, o incluso la definición de funciones (simplemente hacen #define sy typedef 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 hospedada, encontrará que solo hay muy pocas funciones que realmente necesiten una interfaz con "el sistema" de cualquier manera, con el resto de la biblioteca implementable por encima de esos "primitivos". Al implementar el PDCLib , hice un esfuerzo para aislarlos en un subdirectorio separado para una identificación fácil al transferir la biblioteca a una nueva plataforma (ejemplos para el puerto de Linux entre paréntesis):

  • getenv() ( extern char * * environ )
  • system() ( fork() / execve() / wait() )
  • malloc() y free() ( brk() / sbrk() )
  • _Exit() ( _exit() )
  • time() (no implementado todavía)

Y para <stdio.h> (posiblemente el más "involucrado con el sistema operativo" de los encabezados C99):

  • alguna forma de abrir un archivo ( open() )
  • alguna forma de cerrarla ( close() )
  • alguna forma de eliminarlo ( unlink() )
  • alguna forma de cambiarle el nombre ( link() / unlink() )
  • alguna forma de escribirle ( write() )
  • alguna forma de leerlo ( read() )
  • alguna forma de reposicionar dentro de él ( lseek() )

Ciertos detalles de la biblioteca son opcionales, ya que el estándar simplemente los ofrece para que se implementen de manera estándar, pero no hace que tal implementación sea un requisito.

  • La función time() puede devolver legalmente (time_t)-1 si no hay mecanismos de cronometraje disponibles.

  • Los manejadores de señales descritos para <signal.h> no deben ser invocados por otra cosa que no sea una llamada a raise() , no hay ningún requisito de que el sistema envíe algo así como SIGSEGV a la aplicación.

  • El encabezado C11 <threads.h> , que es (por razones obvias) muy dependiente del sistema operativo, no se debe proporcionar en absoluto si la implementación define __STDC_NO_THREADS__ ...

Hay más ejemplos, pero no los tengo a mano en este momento.

El resto de la biblioteca se puede implementar sin ayuda del entorno. (*)

(*) Advertencia: la implementación de PDCLib aún no está completa, así que podría haber pasado por alto una o dos cosas. ;-)

    
respondido por el DevSolar
4

El estándar C se define en realidad por separado del entorno operativo. No se supone que un sistema operativo host esté presente, y las partes que dependen del host se definen como tales.

Es decir, el estándar C ya es bastante simple.

Por supuesto, esas 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 completa.

    
respondido por el jdv
2

Cuando lo usas baremetal, descubres algunas dependencias no implementadas y tienes 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 gancho en el código, que debe ser implementado por el usuario para imponer los compromisos de hardware. Aquí puedo implementarlo o hacer mi propio malloc () si creo que podría hacer uno mejor para el hardware incorporado, principalmente para otros usos, no solo sprintf.

    
respondido por el Ayhan
1

Ejemplo ejecutable mínimo de Newlib

Aquí ofrezco un exit.c :

#include <stdio.h>
#include <stdlib.h>

void main(void) {
    exit(0);
}

y en un archivo C separado , implementamos common.c con ARM semihosting :

void _exit(int status) {
    __asm__ __volatile__ ("mov r0, #0x18; ldr r1, =#0x20026; svc 0x00123456");
}

Los otros syscalls típicos que implementará son:

  • exit para mostrar los resultados al host. Esto se puede hacer con:

    • más semihosting
    • un hardware UART
  • write para brk .

    ¡Fácil en baremetal, ya que no tenemos que preocuparnos por la paginación!

TODO Me pregunto si es realista alcanzar la ejecución de syscalls de programación anticipada sin entrar en un RTOS .

Lo bueno de Newlib, es que implementa todas las cosas que no son específicas del sistema operativo como malloc para ti, y te 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 necesita string.h , entonces no tiene que proporcionar un exit .

El árbol fuente de Newlib ya tiene algunas implementaciones, incluida una implementación de semihosting ARM en print , pero en su mayor parte tiene que implementar el suyo propio. 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 de C. Mi configuración se encarga de eso automáticamente con este script , por lo que es un script . utiliza las configuraciones de newlib que se encuentran en % aparente y / o el contenido de un paquete.

Creo que C ++ también funcionará, pero TODO lo prueba.

    

Lea otras preguntas en las etiquetas