STM32 - Embedded IDE - GCC - rt_thread_nano的终端msh>不工作的排查与解决
导言
解决方案来自该csdn博文:https://blog.csdn.net/a183635870/article/details/126556614
明明在board.c已经实现了函数rt_hw_console_output()
与rt_hw_console_getchar()
,但是终端msh>没有正常工作。
一、解决方案
/* section information for finsh shell */. = ALIGN(4);__fsymtab_start = .;KEEP(*(FSymTab))__fsymtab_end = .;. = ALIGN(4);__vsymtab_start = .;KEEP(*(VSymTab))__vsymtab_end = .;. = ALIGN(4);/* section information for initial. */. = ALIGN(4);__rt_init_start = .;KEEP(*(SORT(.rti_fn*)))__rt_init_end = .;
如上所示,重新编译程序。
如上所示,终端msh>恢复正常了!
二、问题根源
2.1、FSymTab与VSymTab
RT-Thread的finsh shell系统依赖于符号表机制来发现和执行命令。当你使用宏如MSH_CMD_EXPORT、FINSH_FUNCTION_EXPORT等导出命令时,这些宏会将命令信息存储在特定的段中:
- FSymTab段 - 存储函数符号表
- VSymTab段 - 存储变量符号表
链接脚本的作用
这段代码:
/* section information for finsh shell */. = ALIGN(4);__fsymtab_start = .;KEEP(*(FSymTab))__fsymtab_end = .;. = ALIGN(4);__vsymtab_start = .;KEEP(*(VSymTab))__vsymtab_end = .;. = ALIGN(4);
起到了关键作用:
- 定义符号表边界:
__fsymtab_start
和__fsymtab_end
标记函数符号表的开始和结束位置 - 收集符号:
KEEP(*(FSymTab))
确保所有FSymTab段的内容都被保留在链接后的可执行文件中 - 提供地址引用:RT-Thread在运行时通过这些符号来遍历所有注册的命令
RT-Thread如何使用这些符号
从源码可以看到,在shell.c
的finsh_system_init()
函数中:
系统会调用这些函数来初始化符号表,让shell知道有哪些命令可用。
为什么没有这段代码会失败
如果链接脚本中没有定义这些段和符号:
- 符号丢失:链接器可能会丢弃FSymTab和VSymTab段的内容
- 边界未定义:
__fsymtab_start
等符号未定义,导致RT-Thread无法找到符号表 - 命令无法注册:所有通过
MSH_CMD_EXPORT
等宏导出的命令都无法被发现 - shell无法工作:msh>提示符出现,但输入任何命令都会提示"command not found"
这就是为什么添加这段代码后RT-Thread的msh>终端就能正常工作了!
2.2、.rti_fn*
还有最后一段
/* section information for initial. */. = ALIGN(4);__rt_init_start = .;KEEP(*(SORT(.rti_fn*)))__rt_init_end = .;
这段代码同样是不可缺少的,它与RT-Thread的自动初始化系统密切相关。删除这段代码会导致msh>无法正常工作:
RT-Thread自动初始化系统的工作原理
- RT-Thread使用一套自动初始化机制,通过宏来自动注册初始化函数:
- INIT_BOARD_EXPORT(fn) - 板级初始化
- INIT_DEVICE_EXPORT(fn) - 设备初始化
- INIT_COMPONENT_EXPORT(fn) - 组件初始化
- INIT_ENV_EXPORT(fn) - 环境初始化
- INIT_APP_EXPORT(fn) - 应用初始化
这段代码的作用是:
- 收集初始化函数:
KEEP(*(SORT(.rti_fn*)))
收集所有.rti_fn
段的内容 - 按优先级排序:SORT()确保初始化函数按正确的顺序执行
- 定义边界符号:
__rt_init_start
和__rt_init_end
标记初始化函数表的边界
2.3、总结
总结:
- 第一段代码(FSymTab/VSymTab)负责命令发现和注册
- 第二段代码(.rti_fn*)负责系统自动初始化
两者缺一不可,共同保证RT-Thread系统的正常运行!