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。 输入 输入的第一行为矩阵的行数和列数,接下…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
