나는 주로 리눅스를 이식 한 장치에서 개발을하고 있기 때문에 표준 C 라이브러리는 표준화 된 동작을 가진 시스템 호출을 구현하여 많은 기능을 제공합니다.
그러나 베어 메탈의 경우 기본 OS가 없습니다. ac 라이브러리를 구현하는 방법과 관련된 표준이 있습니까? 아니면 다른 BSP를 제공하는 새 보드로 전환 할 때 라이브러리 구현의 특성을 다시 배워야합니까?
나는 주로 리눅스를 이식 한 장치에서 개발을하고 있기 때문에 표준 C 라이브러리는 표준화 된 동작을 가진 시스템 호출을 구현하여 많은 기능을 제공합니다.
그러나 베어 메탈의 경우 기본 OS가 없습니다. ac 라이브러리를 구현하는 방법과 관련된 표준이 있습니까? 아니면 다른 BSP를 제공하는 새 보드로 전환 할 때 라이브러리 구현의 특성을 다시 배워야합니까?
답변:
그렇습니다. 표준 인 C 표준 라이브러리가 있습니다. 라이브러리 함수는 "완전히 터진"OS 나 다른 OS를 전혀 필요로하지 않으며, "베어 메탈 (bare metal)"코드에 맞게 여러 가지 구현이 있으며 Newlib은 아마도 가장 잘 알려져 있습니다.
Newlib을 예로 들면, 주로 시스템에서 파일 및 메모리 할당이 처리되는 방식의 핵심 기능 중 일부를 작성해야합니다. 공통 대상 플랫폼을 사용하는 경우 누군가 이미이 작업을 수행했을 가능성이 있습니다.
linux (아마도 OSX 및 cygwin / msys?) 및 type man strlen
을 사용하는 경우와 같은 섹션이 있어야 CONFORMING TO
구현이 특정 표준을 준수 함을 알 수 있습니다. 이 방법을 사용하면 사용중인 것이 표준 기능인지 또는 특정 OS에 의존하는지 알아낼 수 있습니다.
stdlib
구현 하는지 궁금 stdio
합니다. 같은 fopen()
, fclose()
, fread()
, fwrite()
, putc()
와 getc()
? 그리고 malloc()
OS와 대화 하지 않고 어떻게 작동합니까?
getchar
및 putchar
이는 하드웨어의 UART에 대해 알고; 그 printf
위에 Newlib 레이어 가 있습니다. 파일 I / O도 마찬가지로 몇 가지 기본 요소에 의존합니다.
stdin
과 stdout
과 stderr
(어떤을 담당 putchar()
하고 getchar()
다음 또한 대한 쓰기 접착제에 있고, 플랫폼은 플래시와 같은 파일 저장이 있으면하는 UART에 /에서 / O를 내가 지시하는). 당신은 할 수있는 수단이 있어야 malloc()
하고 free()
. 이러한 문제를 해결하면 포함 된 대상 ( argv
또는 없음 argc
) 에서 휴대용 C를 거의 실행할 수 있다고 생각합니다 .
ac 라이브러리를 구현하는 방법과 관련된 표준이 있습니까? 아니면 다른 BSP를 제공하는 새 보드로 전환 할 때 라이브러리 구현의 특성을 다시 배워야합니까?
먼저, C 표준은 "호스트 된"구현 (기본 OS에서 지원하는 모든 C 함수의 범위)과 달리 "자립형"구현이라고하는 것을 정의합니다.
"자립형"구현은 C 라이브러리 헤더의 서브 세트, 즉 지원이 필요 하지 않은 서브 세트 또는 함수의 정의 (단지 #define
s 및 typedef
s) 만 정의하면됩니다 .
<float.h>
<iso646.h>
<limits.h>
<stdalign.h>
<stdarg.h>
<stdbool.h>
<stddef.h>
<stdint.h>
<stdnoreturn.h>
호스팅 된 구현을 향한 다음 단계를 진행할 때 실제로 어떤 방식 으로든 "시스템"을 인터페이스해야하는 기능은 거의 없으며, 나머지 라이브러리는 "기본적"위에 구현할 수 있습니다. ". PDCLib을 구현할 때 lib를 새로운 플랫폼으로 포팅 할 때 쉽게 식별 할 수 있도록 별도의 하위 디렉토리에 이들을 분리하기 위해 노력했습니다 (리눅스 포트 괄호 안의 예).
getenv()
( extern char * * environ
)system()
( fork()
/ execve()
/ wait()
)malloc()
그리고 free()
( brk()
/ sbrk()
)_Exit()
( _exit()
)time()
(아직 구현되지 않음)그리고 <stdio.h>
(아마도 C99 헤더 중 가장 "OS 관련") :
open()
)close()
)unlink()
)link()
/ unlink()
)write()
)read()
)lseek()
)라이브러리의 특정 세부 사항은 선택 사항이며 표준 은 표준 방식으로 구현되도록 제공 하지만 그러한 구현을 요구 사항으로 만들지는 않습니다.
time()
기능은 법적으로 만 반환 할 수 있습니다 (time_t)-1
시간을 지키는 메커니즘을 사용할 수없는 경우.
에 대해 설명 된 신호 처리기는에 대한 <signal.h>
호출 이외의 다른 방법으로 호출 할 필요 raise()
가 없으며, 시스템이 실제로 응용 프로그램에 비슷한 것을 보낼 필요는 없습니다 SIGSEGV
.
구현이 정의한다면 <threads.h>
(명백한 이유로) OS에 매우 의존적 인 C11 헤더 는 전혀 제공 될 필요가 없습니다 __STDC_NO_THREADS__
...
더 많은 예가 있지만 지금 당장은 없습니다.
나머지 라이브러리는 환경의 도움없이 구현할 수 있습니다. (*)
(*)주의 사항 : PDCLib 구현이 아직 완료되지 않았으므로 한두 가지를 간과했을 수도 있습니다. ;-)
표준 C는 실제로 운영 환경과 별도로 정의됩니다. 호스트 OS가 존재한다는 가정은 없으며 호스트에 의존하는 부분은 그대로 정의됩니다.
즉, C 표준은 이미 꽤 노출 된 금속입니다.
물론, 우리가 좋아하는 언어 부분 인 라이브러리는 종종 핵심 언어가 특정 내용을 호스트하는 곳입니다. 따라서 많은 베어 메탈 플랫폼 도구에 사용되는 일반적인 "xxx-lib"크로스 컴파일러 제품입니다.
Newlib 최소 실행 가능 예제
여기서는 QEMU에서 작동하는 newlib를 보여주는 고도로 자동화되고 문서화 된 예제를 제공합니다 .
newlib을 사용하면 베어 메탈 플랫폼에 대한 자체 시스템 호출을 구현할 수 있습니다.
예를 들어, 위 예제에는 예제 프로그램이 있습니다 exit.c
.
#include <stdio.h>
#include <stdlib.h>
void main(void) {
exit(0);
}
별도의 C 파일에서 common.c
, 우리는 구현 exit
과 ARM은 세미 호스팅 :
void _exit(int status) {
__asm__ __volatile__ ("mov r0, #0x18; ldr r1, =#0x20026; svc 0x00123456");
}
구현할 다른 일반적인 syscall은 다음과 같습니다.
write
결과를 호스트에 출력합니다. 이것은 다음 중 하나를 사용하여 수행 할 수 있습니다.
brk
에 대한 malloc
.
페이징에 신경 쓸 필요가 없으므로 베어 메탈에서 쉽게 사용할 수 있습니다.
TODO Zephyr 또는 FreeRTOS 와 같은 완전한 RTOS 로 들어 가지 않고 선제 적 스케줄링 syscall 실행에 도달하는 것이 현실적인지 궁금합니다 .
Newlib의 멋진 점은 그것이 string.h
당신 과 같은 모든 비 OS 관련 사항 을 구현하고 OS 스텁 만 구현할 수 있다는 것입니다.
또한 모든 스텁을 구현할 필요는 없지만 필요한 스텁 만 구현하십시오. 예를 들어, 프로그램에만 필요 exit
하면을 제공 할 필요가 없습니다 print
.
Newlib 소스 트리에는 ARM 세미 호스팅 구현을 포함하여 이미 일부 구현이 newlib/libc/sys/arm
있지만 대부분의 경우 자체 구현해야합니다. 그러나 작업을위한 견고한 기반을 제공합니다.
Newlib를 설정하는 가장 쉬운 방법은 crosstool-NG를 사용하여 자체 컴파일러를 빌드하는 것입니다. Newlib를 C 라이브러리로 사용하고 싶다고 말하면됩니다. 내 설정은 이 스크립트 를 사용하여 자동으로 처리합니다. 이 스크립트 는에있는 newlib 구성을 사용합니다 crosstool_ng_config
.
C ++도 효과가 있다고 생각하지만 TODO는 그것을 테스트합니다.
베어 메탈을 사용할 때 구현되지 않은 일부 종속성을 발견하고 처리해야합니다. 이러한 모든 종속성은 시스템의 성격에 따라 내부를 조정하는 것입니다. 예를 들어 malloc ()을 사용하는 sprintf ()를 사용하려고했을 때. Malloc은 "t_sbrk"기능 심볼을 코드의 후크 (hook in code)로 가지고 있으며, 하드웨어 구속을 강화하기 위해 사용자가 구현해야합니다. 여기서는 sprintf뿐만 아니라 주로 다른 용도로 임베디드 하드웨어를 위해 더 나은 것을 할 수 있다고 생각하면 그것을 구현하거나 내 malloc ()을 만들 수 있습니다.