Bare Metal
Table of Contents
1. Bare Metal
1.1. overview
baremetal(以及工具链)与 linux 的主要区别:
libc
linux 使用 glibc, baremetal 使用 newlib, 并且会使用 newlib 提供的 libgloss, libnosys 等支持 io, malloc 等原本需要 linux 支持的功能
crt
linux 下使用 gcc 提供的 crt, baremetal 使用了 libgloss 提供的 crt, 但 libgloss 只提供了 crt{0,i,n,begin,end}.o, 没有提供 crt{beginS,endS}.o 等
multilib
baremetal 环境下 multilib 的配置会有些区别, 例如会针对适用于嵌入式环境的扩展 (e,c,…) 定义 multilib
动态链接
baremetal 不支持动态链接(以及 PIE)
其它
baremetal 有时会使用自定义的 linker script, 并禁用 crt 及 libc
1.2. crt
1.2.1. crt0.o
以 riscv 的 crt0.o 为例, 它提供 _start 做为程序入口, _start 的主要功能有:
- 初始化 GP
- 清空 BSS
- 通过 atexit 注册 _libc_fini_array, 以便在程序结束时调用 finit_array
- 通过 _libc_init_array 以调用 init_array
- 调用 main
- exit
它的代码是这样的:
.text .global _start _start : # 初始化 GP .option push .option norelax 1: auipc gp,% pcrel_hi(__global_pointer$) addi gp, gp, % pcrel_lo(1b) .option pop # 清空 bss la a0,_edata la a2, _end sub a2, a2, a0 li a1, 0 call memset # atexit 注册 __libc_fini_array .weak atexit la a0, atexit beqz a0,.Lweak_atexit .weak __libc_fini_array la a0,__libc_fini_array #Register global termination functions call atexit call atexit # 调用 __libc_init_array call __libc_init_array # 调用 main lw a0, 0(sp) #a0 = argc addi a1, sp, __SIZEOF_POINTER__ #a1 = argv li a2, 0 #a2 = envp = NULL call main # exit tail exit .size _start,.- _start
1.2.2. crti.o, crtn.o
for init/finit
1.2.3. crtbegin.o, crtendi.o
for c++
1.2.4. crtbeginS.o, crtendS.o
for c++ shared library
1.3. 实现
baremetal 与 linux 工具链的区别主要体现在 spec 中, spec 的定义和处理是在 `gcc.cc`, 它会使用 config.gcc 中定义的头文件:
riscv*-*-elf* | riscv*-*-rtems*) tm_file="elfos.h newlib-stdint.h ${tm_file} riscv/elf.h" tmake_file="${tmake_file} riscv/t-riscv" riscv*-*-linux*) tm_file="elfos.h gnu-user.h linux.h glibc-stdint.h ${tm_file} riscv/linux.h" tmake_file="${tmake_file} riscv/t-riscv riscv/t-linux"
其中 linux.h 和 elf.h 会定义不同的 spec, 让 gcc/ld 使用不同的 STARTFILE_SPEC 和 LIB_SPEC 等
1.4. 其它
1.4.1. 禁用 crt/libc
baremetal 有时会使用下面的 flag 禁用 crt/libc/libgcc:
nodefaultlibs
不使用 libc, libgcc
nostartfiles
不使用 crt0.o 等 startfiles
nostdlib
nodefaultlibs + nostartfiles
1.4.2. qemu arm bare metal example
https://balau82.wordpress.com/2010/02/28/hello-world-for-bare-metal-arm-using-qemu/
为了验证 kws 在 mips bare metal 上的情况, 使用 qemu arm bare metal example 来测试 bare metal 的基本概念
支持 bare metal 的方法:
- 针对板子写 start.s, 初始化 sp 等, 然后跳转到 main
- linker script 需要把 start.o 放在板子要求的地址上, 同时需要提供一些符号, 例如 newlib 中的 _sbrk 需要 linker script 定义 `end` 以后才能支持 malloc
- 通过 nosys.specs 使用 libnosys 给 _fork, _exit 等函数提供 dummy 实现, 避免编译不过