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
命令的名称和描述字符串变量的链接地址和段位置。链接地址是:0x0800ff69
和 0x0800ff71
,链接段是.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
的地址,分别是0x0800ff69
和 0x0800ff71
,__fsym_version
的地址是0x080100c4
。0x08
开始的地址表示ROM上的地址,即FLASH地址空间。
打开编译生成的rtthread.bin
文件,搜索version
。version
符号出现的地址正好是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文件中链接的地址一致。
相关文章:

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_CM…...

电脑麦克风没声音怎么办?这3招就可以解决!
最近有用户在使用电脑麦克风进行视频录制时,发现麦克风没有声音。这是什么原因?电脑麦克风没有声音怎么办?关于解决方案,我专门整理了三种方法来帮你们,一起来看看吧! 操作环境: 演示机型&#…...

【C++】运算符重载
运算符重载 C为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名以及参数列表。其返回值类型和参数列表与普通的函数类型。 函数名字为:关键字operator后面接需要重载的运算符号…...

什么是眼图?(扫盲向)
什么是眼图?(扫盲向) Ref: What’s eye diagram? 1 基础图示 眼图 2 用途 常用于评估差分链路中的信号传输质量 "眼睛"张得越开,链路信号质量越好 3 观测原理 眼图是传输信号序列在时域上的叠加 4 观测参数 4…...

【C++】类与对象(二)
前言 在前一章时我们已经介绍了类与对象的基本知识,包括类的概念与定义,以及类的访问限定符,类的实例化,类的大小的计算,以及C语言必须传递的this指针(C中不需要我们传递,编译器自动帮我们实现&…...

【软考】系统集成项目管理工程师(二十一)项目收尾管理
1. 项目验收2. 项目总结3. 系统维护4. 项目后评价补充:人员转移和资源遣散广义的系统集成项目收尾管理工作通常包含四类典型的工作:项目验收工作、项目总结工作、系统维护工作 以及 项目后评价工作,此外项目团队成员的后续工作也应在收尾管理时妥善安排;狭义的系统集成项目…...
关于公钥与私钥的一点看法
故事的起源 私密性 之前,用户a想给用户b发消息,a希望他自己发出现的消息,只能被b读懂。也就是说a希望发出去的数据是被加密过的,收到消息的人可以是b,c,d,e等等。但是只有b能被读懂。 这个需求…...

深入React源码揭开渲染更新流程的面纱
转前端一年半了,平时接触最多的框架就是React。在熟悉了其用法之后,避免不了想深入了解其实现原理,网上相关源码分析的文章挺多的,但是总感觉不如自己阅读理解来得深刻。于是话了几个周末去了解了一下常用的流程。也是通过这篇文章…...

32个关于FPGA的学习网站
语言类学习网站 1、HDLbits 网站地址:https://hdlbits.01xz.net/wiki/Main_Page 在线作答、编译的学习Verilog的网站,题目很多,内容丰富。非常适合初学Verilog的人!!! 2、牛客网 网站地址:http…...
5分钟快速上手Promise使用
promise 是处理异步编程的一种处理方式,可以将异步操作按照同步操作的方式编写。是一个对象或者构造函数,里面存放着某个未来才会执行的结果的方法(一般就是异步操作) 自己身上有all、reject、resolve这几个方法,原型上…...

大客户市场:阿里云、腾讯云、华为云“贴身肉搏”
配图来自Canva可画 近年来,随着中国逐渐进入数字化经济快车道,国内企业数字化、智能化升级已是刻不容缓。而为了帮助自身或其他企业实现数字化转型升级,阿里、腾讯、百度、京东、字节、网易、华为等众多国内知名企业早在多年以前,…...
华为OD机试 - 求字符串中所有整数的最小和(Python)| 真题+思路+代码
求字符串中所有整数的最小和 题目 说明 字符串 s,只包含 a-z A-Z + - ;合法的整数包括 1) 正整数 一个或者多个0-9组成,如 0 2 3 002 102 2)负整数 负号 - 开头,数字部分由一个或者多个0-9组成,如 -0 -012 -23 -00023输入 包含数字的字符串 输出 所有整数的最小和 …...

企业电子招投标采购系统源码之首页设计
功能模块: 待办消息,招标公告,中标公告,信息发布 描述: 全过程数字化采购管理,打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力,为…...

浅谈一下前端工作中全流程多层次的四款测试工具
在应届生找工作的时候,我们经常会见到一条招聘要求:要求实习经历。或者 有实习经历者优先。 为什么大部分公司在招聘时,都要求你必须有实习经历? 商业项目与个人项目不同,一段实习经历,能够熟悉公司中成熟…...

【运算放大器】反相放大电路仿真应用
目录 一、反相放大电路原理(简化电路) 二、反相放大电路电路原理(实际特性) 2.1原理图 2.2实际电路 三、虚短 虚断 3.1 虚短 3.2 虚断 四、作业 4.1 (反相)放大电路设计 4.2 LM741芯片 五、标准…...

数组的操作
1.splice 1.splice 是数组的一个方法,使用这个方法会改变原来的数组结构,splice(index ,howmany , itemX);这个方法接受三个参数,我们在使用的时候可根据自己的情况传递一个参数&…...

Python - 文件基础操作
目录 文件的读取 open()打开函数 read类型 read()方法 readlines()方法 readline()方法 for循环读取文件行 close() 关闭文件对象 with open 语法 文件的写入 文件的追加 文件的读取 操作 功能 文件对象 open(file, mode, encoding) 打开文件获得文件对象 文件…...

react的useState源码分析
前言 简单说下为什么React选择函数式组件,主要是class组件比较冗余、生命周期函数写法不友好,骚写法多,functional组件更符合React编程思想等等等。更具体的可以拜读dan大神的blog。其中Function components capture the rendered values这句…...

SharpImpersonation:一款基于令牌和Shellcode注入的用户模拟工具
关于SharpImpersonation SharpImpersonation是一款功能强大的用户模拟工具,该工具基于令牌机制和Shellcode注入技术实现其功能,可以帮助广大研究人员更好地对组织内部的网络环境和系统安全进行分析和测试。 该工具基于 Tokenvator的代码库实现其功能&a…...
华为OD机试 - 最大相连男生数(Python)| 真题+思路+代码
最大相连男生数 题目 学校组织活动,将学生排成一个矩形方阵。 请在矩形方阵中找到最大的位置相连的男生数量。 这个相连位置在一个直线上,方向可以是水平的、垂直的、成对角线的或者反对角线的。 注:学生个数不会超过 10000。 输入 输入的第一行为矩阵的行数和列数,接下…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...

uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
鸿蒙(HarmonyOS5)实现跳一跳小游戏
下面我将介绍如何使用鸿蒙的ArkUI框架,实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...