STM32板自制Linux init程序调用write失败:谁负责打开标准文件描述符?
问题解答
错误码说明
错误码-9对应Linux内核定义的EBADF(无效文件描述符),这表明你的init程序调用write(1, ...)时,文件描述符1并未被打开。
疑问解答
1. 为何无标准库的Linux init进程中不存在0、1、2文件描述符?
Linux内核不会自动为PID 1进程打开标准输入/输出/错误描述符(0、1、2)。内核启动阶段会初始化控制台硬件(比如你的RS232串口),但不会主动将硬件设备关联到用户进程的标准文件描述符上。
PID 1是系统首个用户态进程,没有父进程能继承已打开的文件描述符。如果init程序自身不主动打开并配置这些描述符,0、1、2会处于未分配状态,自然无法通过它们完成IO操作。
2. 究竟是谁负责打开这些标准文件描述符?
- 标准C库:使用标准C库的常规用户程序,libc的启动代码(
_start函数)会在进入main前,自动尝试打开/dev/console(或系统配置的控制台设备),并将其文件描述符复制到0、1、2,完成标准IO描述符的初始化。 - 无标准库的init程序:这种场景下,必须由init程序自行手动完成标准描述符的初始化。你需要在汇编代码中调用
open系统调用打开对应串口设备节点(比如/dev/ttyS0,具体取决于STM32的串口配置),再通过dup2系统调用将打开的文件描述符复制到0、1、2。
修复建议
在你的汇编init程序中添加以下步骤:
- 调用
open系统调用打开控制台设备(如/dev/console或/dev/ttyS0),获取文件描述符fd; - 调用
dup2(fd, 0)将该文件描述符复制为stdin; - 调用
dup2(fd, 1)复制为stdout; - 调用
dup2(fd, 2)复制为stderr; - 之后再执行
write(1, "blabla", 6)即可正常输出到RS232控制台。
注意:制作initfs时需确保包含对应设备节点,可通过mknod命令创建,比如mknod /dev/ttyS0 c 4 64(主、次设备号需匹配你的内核配置)。
内容的提问来源于stack exchange,提问作者sibislaw
相关产品推荐
相关产品推荐

