当前位置: 首页 > news >正文

RT-Thread MSH_CMD_EXPORT分析

RT-Thread MSH_CMD_EXPORT分析

1. 源码分析

在rt-thread中,使用FinSH,可以支持命令行。在源码中,使用MSH_CMD_EXPORT导出函数到对应命令。

extern void rt_show_version(void);
long version(void)
{rt_show_version();return 0;
}
MSH_CMD_EXPORT(version, show RT-Thread version information);

MSH_CMD_EXPORT是一个宏:

#define MSH_CMD_EXPORT(command, desc)   \MSH_FUNCTION_EXPORT_CMD(command, command, desc)#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc)                      \const char __fsym_##cmd##_name[] rt_section(".rodata.name") = #cmd;    \const char __fsym_##cmd##_desc[] rt_section(".rodata.name") = #desc;   \rt_used const struct finsh_syscall __fsym_##cmd rt_section("FSymTab")= \{                           \__fsym_##cmd##_name,    \__fsym_##cmd##_desc,    \(syscall_func)&name     \};

嵌套定义为MSH_FUNCTION_EXPORT_CMD

这里的rt_section也是一个宏:

#define rt_section(x)               __attribute__((section(x)))

在ARM中,这是编译器识别的一个符号。用来指定编译后数据存放的位置。

这里相当于是定义__fsym_version_name__fsym_version_desc,将其放到.rodata.name段中。这两个字符串分别是命令对应的名称和描述。又定义了一个结构体__fsym_version,用来存放命令的名称,描述和函数指针。

struct finsh_syscall
{const char     *name;       /* the name of system call */
#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB)const char     *desc;       /* description of system call */
#endifsyscall_func func;      /* the function address of system call */
};

函数指针指向的函数和命令同名。将定义的finsh_syscall放到FSymTab段中。

没导出一个命令,就会在.rodata.name段中多两个字符串,FSymTab段中多一个struct finsh_syscall结构体。

导出所有需要的命令后,这里FSymTab可以看做是一个数组,元素类型是struct finsh_syscall,长度是所有命令的总和。

2. map文件

编译时,可以指定生成.map文件。KEIL默认会输出map文件到编译目录。

在map文件中搜索__fsym_version,可以找到version命令的名称和描述字符串变量的链接地址和段位置。链接地址是:0x0800ff690x0800ff71,链接段是.rodata.name,与前面分析一致。可以看到上面和下面确实也是其它命令的名称和描述。

在这里插入图片描述

还能搜索到__fsym_version 结构体的链接地址和段。地址是0x080100c4,段是FSymTab。这里可以看到,所有命令的结构体都存到这个段的,间隔也是正好是12个字节,和struct finsh_syscall结构体长度一致。看这个情况,应该是照编译时的按顺序摆放所有结构体到这个段中。

在这里插入图片描述

这里通过编译时,将这个段的起始地址给到msh,然后通过查这个表来对比命令的名称,匹配上了,就执行相应的函数指针,从而就能够执行对应的命令的函数。

查表:

static cmd_function_t msh_get_cmd(char *cmd, int size)
{struct finsh_syscall *index;cmd_function_t cmd_func = RT_NULL;for (index = _syscall_table_begin;index < _syscall_table_end;FINSH_NEXT_SYSCALL(index)){if (strncmp(index->name, cmd, size) == 0 &&index->name[size] == '\0'){cmd_func = (cmd_function_t)index->func;break;}}return cmd_func;
}

_syscall_table_begin_syscall_table_end 变量对应就是FSymTab 段的起始地址。

void finsh_system_function_init(const void *begin, const void *end)
{_syscall_table_begin = (struct finsh_syscall *) begin;_syscall_table_end = (struct finsh_syscall *) end;
}
int finsh_system_init(void)
{extern const int FSymTab$$Base;extern const int FSymTab$$Limit;finsh_system_function_init(&FSymTab$$Base, &FSymTab$$Limit);
}

这里这两个全局变量找不到定义的位置。查找资料得知,FSymTab$$Base表示FSymTab段的开始地址,FSymTab$$Limit表示FSymTab段的结束地址。

参考:https://www.cnblogs.com/King-Gentleman/p/4573652.html

3. bin文件

前面分析得到了__fsym_version_name__fsym_version_desc的地址,分别是0x0800ff690x0800ff71__fsym_version 的地址是0x080100c40x08开始的地址表示ROM上的地址,即FLASH地址空间。

打开编译生成的rtthread.bin文件,搜索versionversion符号出现的地址正好是ff69,是字符串 “version”,紧接着是描述部分内容 “show RT-Thread version information”。由于是bin文件,是相对地址,因此地址前面没有0x08

在这里插入图片描述

在跳到100c4地址:

在这里插入图片描述

这里开始的12个字节,对应的就是__fsym_version结构体中各个字段的内容。注意大小端转换,命令的名称地址69 ff 00 08,即0x0800ff69,描述对应的地址是71 ff 00 08,即0x0800ff71。函数指针对应的地址是4d ea 00 08,即0x0800ea4d,和map文件中链接的地址一致。

在这里插入图片描述

http://www.lryc.cn/news/4630.html

相关文章:

  • 电脑麦克风没声音怎么办?这3招就可以解决!
  • 【C++】运算符重载
  • 什么是眼图?(扫盲向)
  • 【C++】类与对象(二)
  • 【软考】系统集成项目管理工程师(二十一)项目收尾管理
  • 关于公钥与私钥的一点看法
  • 深入React源码揭开渲染更新流程的面纱
  • 32个关于FPGA的学习网站
  • 5分钟快速上手Promise使用
  • 大客户市场:阿里云、腾讯云、华为云“贴身肉搏”
  • 华为OD机试 - 求字符串中所有整数的最小和(Python)| 真题+思路+代码
  • 企业电子招投标采购系统源码之首页设计
  • 浅谈一下前端工作中全流程多层次的四款测试工具
  • 【运算放大器】反相放大电路仿真应用
  • 数组的操作
  • Python - 文件基础操作
  • react的useState源码分析
  • SharpImpersonation:一款基于令牌和Shellcode注入的用户模拟工具
  • 华为OD机试 - 最大相连男生数(Python)| 真题+思路+代码
  • GIS在地质灾害危险性评估与灾后重建中的实践技术应用及python机器学习灾害易发性评价模型建立与优化
  • 2.13、进程互斥的硬件实现方法
  • Leetcode力扣秋招刷题路-2335
  • C语言深度解剖-关键字(6)
  • [多线程进阶]CAS与Synchronized基本原理
  • 【Linux系统编程】02:文件操作
  • 华为OD机试 - 去除多余空格(Python)| 真题+思路+代码
  • 百趣代谢组学分享,补充α-酮酸的低蛋白饮食对肾脏具有保护作用
  • json对象和formData相互转换
  • 【c++面试问答】常量指针和指针常量的区别
  • Ubuntu18下编译android的ffmpeg经验