学习原因
工作中,使用同事开发的调试软件,输入参数打印的函数名就可以打印参数,但看不到代码实现,只能用自己微薄的知识积累去猜一下,之前尝试过,专门写一个函数,去解析编译生成的map文件,就可以通过函数名去找到函数的地址,然后用函数指针去运行就可以了,最近工作之余在学习RT-Thread的内核源码,刚好看到了Finsh组件,可以在命令行输入函数名运行,所以就简单学习了下;
自定义MSH命令
举例引入
如下是最简单的“hello world"函数, 在函数定义下面有一行宏,纸面意思是Finsh函数导出,下面对宏进行分析:
void hello(void)
{
printf("hello RT-Thread!\n");
}
FINSH_FUNCTION_EXPORT(hello, say hello world);
宏定义说明
先看下RT-Thread官方文档对如下宏定义的说明:
FINSH_FUNCTION_EXPORT(hello, say hello world);
宏定义源码分析
#define FINSH_FUNCTION_EXPORT(name, desc) \
FINSH_FUNCTION_EXPORT_CMD(name, name, desc)
/* else分支下的宏定义 */
#define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
const char __fsym_##cmd##_name[] SECTION(".rodata.name") = #cmd; \
const char __fsym_##cmd##_desc[] SECTION(".rodata.name") = #desc; \
RT_USED const struct finsh_syscall __fsym_##cmd SECTION("FSymTab")= \
{ \
__fsym_##cmd##_name, \
__fsym_##cmd##_desc, \
(syscall_func)&name \
};
/* 上面宏定义中调用的宏的定义 */
#define SECTION(x) __attribute__((section(x)))
#define RT_USED __attribute__((used))
/* 上面宏定义中使用的结构体定义 */
struct finsh_syscall
{
const char* name; /* the name of system call */
const char* desc; /* description of system call */
syscall_func func; /* the function address of system call */
};
/* 上面宏定义中使用的函数指针定义 */
typedef long (*syscall_func)(void);
宏展开后的真相
可以看到展开之后,是一个finsh_syscall结构体类型的变量"__fsym_hello",在后续章节可以得到证实;