关于newlib中的libgloss和libnosys
- Newlib的构成
- libgloss的作用
- 提供启动代码
- 提供底层I/O支持
- 提供底层系统函数
- libnosys是什么鬼
- 什么时候需要libnosys
- 引用libnosys
libgloss提供启动代码、底层I/O支持、底层系统函数。libnosys提供空的底层系统函数以便程序通过编译。
Newlib的构成
Newlib由三部分构成:libgloss、libc、libm,三者在Newlib源代码中的存储位置如下。
- newlib-x.y.z
- libgloss
- newlib
- libc
- libm
libc是标准C库,libm是标准数学库,那libgloss是干啥的?
libgloss的作用
Libgloss is a library for all the details that usually get glossed over. This library refers to things like startup code, and usually I/O support for gcc and C library.
这段话的来源:Embed with GNU - Libgloss。也就是说libgloss是提供启动代码和底层I/O支持的。
2022年2月23日追加:C库的部分函数需要引用系统调用,裸机系统没有这些系统调用,那么就由C库中的libgloss来提供,gloss这个单词的本意是“假象”。
提供启动代码
libgloss目录下有很多和处理器相关的子目录,例如有子目录arm、m68k、i386、mips等。这些子目录下都有一个crt0.S汇编文件,这个就是启动代码所在的源文件了,可能还会有其它的汇编文件,这和具体的处理器有关。
提供底层I/O支持
libgloss目录下还包含底层I/O支持相关的源代码,例如write.c源文件定义了write
函数,当程序中引用了printf
等标准输出函数时,最终printf
会调用write
函数进行输出,如果没有定义write
函数,那么链接就失败了。
提供底层系统函数
libgloss目录下还包含底层系统函数相关的源代码,例如kill.c源文件定义了kill
系统函数,getpid.c源文件定义了getpid
系统函数。虽然在libgloss中,很多系统函数都被定义成空函数,没有实际的作用,但对程序完成正常的链接起到重要作用。特别是在引用了第三方库,而第三方库又引用系统函数的情况下,libgloss就显得特别有用了,这种情况下如果没有libgloss那么链接是会失败的。
libnosys是什么鬼
libgloss目录下除了和处理器相关的子目录外,还有个很特别的子目录,那就是libnosys目录,这个目录下的源文件重新定义了libgloss的所有函数,但是所有函数都是空的,例如对照一下libgloss/write.c和libgloss/libnosys/write.c这两个文件。
// libgloss/write.c
int
_DEFUN (write, (fd, buf, nbytes),
int fd _AND
char *buf _AND
int nbytes)
{
int i;
for (i = 0; i < nbytes; i++) {
if (*(buf + i) == '\n') {
outbyte ('\r');
}
outbyte (*(buf + i));
}
return (nbytes);
}
libgloss/write.c定义的write
函数调用用户定义的outbyte
函数输出内容。
// libgloss/libnosys/write.c
int
_DEFUN (_write, (file, ptr, len),
int file _AND
char *ptr _AND
int len)
{
errno = ENOSYS;
return -1;
}
libgloss/libnosys/write.c定义的write
函数设置了错误代码,然后什么也不做,因此纯粹是个stub
函数,完全是为了链接通过而定义的。
什么时候需要libnosys
如果程序并不实际使用系统函数,但是某些代码引用了系统函数,那么可以引入libnosys,以便通过编译。
引用libnosys
给GCC传递编译选项-lnosys
即可引用libnosys,这时编译器将链接到libnosys.a,这个文件位于ARM GCC安装目录的arm-none-eabi\lib子目录下。