请选择 进入手机版 | 继续访问电脑版

硬汉嵌入式论坛

 找回密码
 立即注册
查看: 18491|回复: 163
收起左侧

[STM32H7] 论坛首发,STM32实现动态加载模组(似于Windows的dll),使用MDK编译动态库类

  [复制链接]

12

主题

152

回帖

203

积分

高级会员

积分
203
发表于 2021-12-5 02:10:49 | 显示全部楼层 |阅读模式
   最近看到好多嵌入式操作系统都具有动态加载的相关功能,如Threadx和RT-Thread的moudle功能,但这些功能都与自身系统耦合很严重,大部分都要依赖于自己的工具链。考虑到MDK5使用的人最多,因此决定采用MDK5的相关工具链实现一个方便移植的动态加载实现。本程序中elf文件解析部分参照了RT-Thread的Moudle实现。实现过程中查阅了很多的资料,中间也遇到了蛮多的问题,索性最后都解决了。非常感谢硬汉大哥的文档教程,在里面学到了很多东西,本帖也算是我对论坛的一点点回馈,希望能帮助到有需要的人,相关代码与工程我都会放到附件中,供大家参考。
1.什么是动态加载?

  按照程序的加载方式进行分类,可以分为静态加载和动态加载。静态加载是指所以程序代码都在编译期予以确定,所有程序都需要存储在ROM中,程序尺寸受限于flash的尺寸,运行速度较快,无需预加载。动态加载是在编译期间,依靠函数或者其他手段,从其他的存储介质中将程序加载ram中运行,与静态加载相比更加灵活,可以很方便的进行程序升级,可以把暂时不需要使用的库释放掉,在需要使用的时候在将其加载到内存中,程序尺寸可以做的很大,可以很方便的实现APP程序。
2.程序功能介绍
  本程序实现的是在STM32中实现程序的动态加载,使用起来与windows的dll类似。程序使用dl_load_lib加载相应的库文件到句柄中,加载成功后可使用dl_get_func,通过函数名获得相应函数指针,在不需要使用时可使用dl_destroy_lib对句柄进行释放。
3.程序使用平台介绍
  本程序使用软件平台位MDK5的V6编译器,语法标准采用C99,移植了FATFS作为文件系统,使用楼主自己编写的内存管理函数进行动态内存的管理,硬件平台位STM32H743。
  相关帖子:论坛首发,内存管理算法,支持malloc,realloc,align_alloc,配有内存碎片合并算法(v1.2)
https://www.armbbs.cn/forum.php? ... 6&fromuid=24016
(出处: 硬汉嵌入式论坛)
4.实现原理简介
  实现STM32动态加载的问题主要有以下几个:
  问题1:被动态加载的APP程序中,程序的基地址是伴随着动态内存变化的,这样就会产生重定位问题,APP中定义数据的地址也会随着程序基地址的改变而改变,如何将这种改变正确的传入到APP程序中?
  解决方案:在我们编程时,编译输出的文件都有一种共同的文件格式:elf文件格式,elf文件格式有很多,其中有的elf文件中,携带了便于实现动态加载的相关信息,可以将重定位操作对代码的影响位置与影响方式以表格的形式表示,Windows,Linux也都是使用这种elf文件实现程序动态加载的。通过对这种特殊的elf文件进行解析,即可实现APP代码的相关数据的重定位。
  问题2:如何生成这样特殊的elf文件呢?
  解决方案:本程序使用的MDK5的V6编译器,利用了armlink中的BPABI中basic_platform特性,实现了这种特殊的elf文件生成。
  问题3:主体程序是通过什么方式调用APP程序呢?
  解决方案:主程序调用APP的程序有两种方法,第一种是直接通过APP的程序入口点进行调用,用于简单调用的情况,每个APP程序的程序入口点为APP程序中的dl_main函数,可以直接通过主体函数dl_get_entry获得APP程序入口点dl_main的函数指针,进而进行调用。第二种是通过函数名进行调用,使用dl_get_func,以函数名的方式在动态链接表中寻找对应的函数指针,进而进行调用。注意:当且仅当APP中定义的函数被DLL_EXPORT修饰时,此函数名才会出现在动态链接表中,才能被主题程序调用。
  问题4:APP程序如何调用主体程序的部分函数?
  解决方案:在主体程序与APP程序间,约定一个固定地址的程序向量表,主体程序把相关函数指针填入到向量表中,APP程序通过查表获取主体程序的函数指针,进而进行调用。
5.程序源码相关文件介绍
  主体程序包含头文件dl_lib.h,.c文件全部加入到工程中即可使用。APP程序编写可以参照附件中的模板工程(源码有点多,有需要在介绍)
APP_Elf_Generate.zip (21.54 KB, 下载次数: 337)


HOST_Elf_parsing.zip (12.81 KB, 下载次数: 317)


评分

参与人数 11金币 +217 收起 理由
Embedded_Proter + 4 很给力!
relax + 20 赞一个!
HenryLAU + 4
awell18 + 8 很给力!
strangeman + 20 很给力!
Colin_Lam + 1
jizai + 20 赞一个!
wawe + 20 很给力!
由崎星空 + 10 赞一个!
caicaptain2 + 10 很给力!
eric2013 + 100 很给力!

查看全部评分

回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-6 23:59:35 | 显示全部楼层
本帖最后由 WZH 于 2021-12-7 00:34 编辑
三尺长剑 发表于 2021-12-6 20:09
有个疑问,动态加载运行的程序性能与正常的有差别吗

在F1和F4上可能会有一点儿差别,动态加载会稍慢点,我这里只有H7的板子,没做测试。
在H7里,由于有Icahe,两个速度基本一样,没啥影响。

APP测试程序

APP测试程序

APP动态加载测试程序

HOST测试程序

HOST测试程序

Host静态加载测试程序

测试效果图

测试效果图

实际测试效果,静态运行的函数与动态加载的函数运行时间基本一致
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-8 17:03:13 | 显示全部楼层
本帖最后由 WZH 于 2022-2-18 17:52 编辑

我在gitee开了个仓库,里面把代码结构改了改,同时加了一个readme文件,方便大家移植,其中代码的实现思路有时间的话我会写一个详细点的文档,最近学业压力较大,可能要等到过年的时候文档才能写完

动态加载的gitee仓库
动态加载的gitee仓库

这个仓库是我平时学习h7时使用的,里面除了动态加载外还集成了一些别的功能,有兴趣的可以看看
完整的使用工程
动态加载简要的文档
STM32动态加载V0.1.pdf (1.12 MB, 下载次数: 333)

ELF文件格式资料
ELF手册-中文版.pdf (551.78 KB, 下载次数: 360)
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
105942
QQ
发表于 2021-12-5 08:26:33 | 显示全部楼层
牛,支持下
回复

使用道具 举报

3

主题

1216

回帖

1225

积分

至尊会员

积分
1225
发表于 2021-12-5 14:03:19 | 显示全部楼层
非常牛!!!!!!
回复

使用道具 举报

0

主题

20

回帖

20

积分

新手上路

中国梦我的梦

积分
20
发表于 2021-12-5 18:06:18 | 显示全部楼层
牛,之前做国网产品的时候,国网提供的操作系统就是动态加载app,知道是rtt的lwp模块,但是一直没有弄清楚。请问动态加载bin文件可以吗?之前国网提供的操作系统就是通过ymodem下载bin,然后再动态启动
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-5 19:11:01 | 显示全部楼层

大家一起交流学习
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-5 19:11:20 | 显示全部楼层
morning_enr6U 发表于 2021-12-5 14:03
非常牛!!!!!!

大家一起交流学习
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-5 19:13:51 | 显示全部楼层
大家可以在评论下动态加载的实战意义大不大,如果大的话,我后面写一篇详细一点的关于实现原理的技术文档。大家一起交流学习
回复

使用道具 举报

3

主题

1216

回帖

1225

积分

至尊会员

积分
1225
发表于 2021-12-5 20:00:52 | 显示全部楼层
这个意义肯定大啊,WZH大侠
回复

使用道具 举报

3

主题

1216

回帖

1225

积分

至尊会员

积分
1225
发表于 2021-12-5 20:03:40 | 显示全部楼层
ThreadX 的Module,是否可以参考下?
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-5 20:15:08 | 显示全部楼层
sxw101320 发表于 2021-12-5 18:06
牛,之前做国网产品的时候,国网提供的操作系统就是动态加载app,知道是rtt的lwp模块,但是一直没有弄清楚 ...

首先,我理解的Bin文件是纯粹的供单片机使用的二进制代码文件,不能直接直接动态加载bin文件,这直接是原理性的限制。RT-Thread也不能直接直接加载通常意义上的Bin文件。在动态加载时,程序代码的存储的位置是需要在运行时确定的,因此在动态加载时,需要更改机器码中所有与地址有关代码,这个操作需要链接器辅助支持(开启链接器的相关选项、编写相应的sct文件,示例的APP工程中有),链接器把与地址有关的代码位置与修改方式,以重定位表的形式附加在elf文件中,单纯的Bin文件中没有这个信息,因此也就不太可能实现。除非这个动态加载是存储在RAM的固定位置的,可那样的话也就不是真正意义上的动态加载了。
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-5 20:17:11 | 显示全部楼层
morning_enr6U 发表于 2021-12-5 20:00
这个意义肯定大啊,WZH大侠

那我有时间的话,写一个详细点的文档供大家参考。
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-5 20:32:47 | 显示全部楼层
morning_enr6U 发表于 2021-12-5 20:03
ThreadX 的Module,是否可以参考下?

其实像这个动态加载的实现,参考ThreadX的moudle意义不大。当时实现陷入死胡同的时候,确实想着参考一下ThreadX的moudle,结果因为之前没用过ThreadX,没找到相关的实现在哪里。。。其实这种动态加载的实现都差不多,都是通过加载具有重定位信息的elf文件实现的,而且有很多的实现,都是需要依赖相应的工具链,比如RT-Thread的实现。我写的这个是根据elf文件结构实现的,好处就是比较通用,基本上只要是带有动态段的elf都支持,不过除了MDK5,其他工具链的就要自己研究研究怎么生成带有动态段的elf了
回复

使用道具 举报

8

主题

102

回帖

136

积分

初级会员

积分
136
发表于 2021-12-5 22:10:38 | 显示全部楼层
sxw101320 发表于 2021-12-5 18:06
牛,之前做国网产品的时候,国网提供的操作系统就是动态加载app,知道是rtt的lwp模块,但是一直没有弄清楚 ...

我也给国网做过东西,SPARC内核芯片,做的数据存储管理单机载荷。。。
回复

使用道具 举报

0

主题

59

回帖

59

积分

初级会员

积分
59
发表于 2021-12-5 22:44:39 | 显示全部楼层
如果是单独加载函数,且函数只用到了入口参数和局部变量应该相当于跳转,比较容易;如果加载的代码需要用到其他函数或全局变量可能需要动态加载内容比较多
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-5 23:10:26 | 显示全部楼层
zhousun 发表于 2021-12-5 22:44
如果是单独加载函数,且函数只用到了入口参数和局部变量应该相当于跳转,比较容易;如果加载的代码需要用到 ...

理解正确。其实重定位部分开销不算很大,而且只需要加载一次,后面在使用就和flash运行程序一致了
回复

使用道具 举报

0

主题

78

回帖

78

积分

初级会员

积分
78
发表于 2021-12-6 09:08:25 | 显示全部楼层
国网系统就喜欢玩一些花里胡哨的东西,比如容器之类的,硬件要求奇高,还要国产化!
回复

使用道具 举报

3

主题

1216

回帖

1225

积分

至尊会员

积分
1225
发表于 2021-12-6 10:14:19 | 显示全部楼层
WZH 发表于 2021-12-5 20:17
那我有时间的话,写一个详细点的文档供大家参考。

感谢,感谢!
回复

使用道具 举报

3

主题

41

回帖

50

积分

初级会员

积分
50
发表于 2021-12-6 10:39:26 | 显示全部楼层
厉害了。学习一下。
回复

使用道具 举报

0

主题

57

回帖

57

积分

初级会员

积分
57
发表于 2021-12-6 12:44:06 | 显示全部楼层
裸机上也实现了动态加载,算是开天辟地的大事件吗
回复

使用道具 举报

12

主题

26

回帖

62

积分

初级会员

积分
62
发表于 2021-12-6 13:55:23 | 显示全部楼层
这个牛, 希望有详细的说明或解析,赞!!!
回复

使用道具 举报

0

主题

4

回帖

4

积分

新手上路

积分
4
发表于 2021-12-6 14:15:25 | 显示全部楼层
牛牛牛 ,这个必须点赞            
回复

使用道具 举报

27

主题

272

回帖

353

积分

高级会员

积分
353
发表于 2021-12-6 14:41:43 | 显示全部楼层
厉害
回复

使用道具 举报

0

主题

10

回帖

10

积分

新手上路

积分
10
发表于 2021-12-6 15:08:39 | 显示全部楼层
WZH 发表于 2021-12-5 19:13
大家可以在评论下动态加载的实战意义大不大,如果大的话,我后面写一篇详细一点的关于实现原理的技术文档。 ...

这个很有意义,H7-TOOL的lua 语言就是这个特点。但是Lua 库需要的空间资源还是很大的。
我的理解是用App 生成 elf文件,再通过一个上位机将 elf文件发送给 HOST,HOST解析这些函数。 是这样的吗?
回复

使用道具 举报

0

主题

9

回帖

9

积分

新手上路

积分
9
发表于 2021-12-6 15:23:41 | 显示全部楼层
期待LZ的教程
回复

使用道具 举报

1

主题

71

回帖

74

积分

初级会员

积分
74
发表于 2021-12-6 15:30:45 | 显示全部楼层
elf文件太大,能做成类似bin不
回复

使用道具 举报

0

主题

34

回帖

34

积分

新手上路

积分
34
发表于 2021-12-6 16:07:15 | 显示全部楼层
很有意义,学习了!
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-6 17:22:57 | 显示全部楼层
nicole088 发表于 2021-12-6 15:08
这个很有意义,H7-TOOL的lua 语言就是这个特点。但是Lua 库需要的空间资源还是很大的。
我的理解是用Ap ...

差不多是这个意思。主机通过elf文件,把文件里程序的机器码回复出来,然后执行。与lua相比,空间资源要小很多很多,运行速度也是lua无法比拟的,另外不需要学习额外的编程语言,缺点就是比较依赖于工具链和芯片架构。
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-6 17:29:20 | 显示全部楼层
252514251 发表于 2021-12-6 15:30
elf文件太大,能做成类似bin不

这个暂时没办法做成bin实现,因为bin文件里缺少用于重定位的辅助信息,不过如果将这个辅助信息保留,在添加到bin文件中,这样的话文件体积就会小很多很多。这个需要开发一个小工具实现这种操作,我没太接触过上位机开发,假期可以考虑实现一个这样的小工具
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-6 17:34:42 | 显示全部楼层
三尺长剑 发表于 2021-12-6 12:44
裸机上也实现了动态加载,算是开天辟地的大事件吗

客气了,只能算是把前人实现过的东西再实现一遍
回复

使用道具 举报

0

主题

57

回帖

57

积分

初级会员

积分
57
发表于 2021-12-6 20:09:43 | 显示全部楼层
WZH 发表于 2021-12-6 17:34
客气了,只能算是把前人实现过的东西再实现一遍

有个疑问,动态加载运行的程序性能与正常的有差别吗
回复

使用道具 举报

3

主题

1216

回帖

1225

积分

至尊会员

积分
1225
发表于 2021-12-7 09:19:36 | 显示全部楼层
期待WZH的精彩教程
回复

使用道具 举报

1

主题

109

回帖

112

积分

初级会员

固件開發工程師

积分
112
QQ
发表于 2021-12-7 11:24:34 | 显示全部楼层
我们这之前用Keil的Overlay实现过不同Code占用相同RAM,楼主这个更彻底,即是ROPI也是RWPI,并且自己写了ELF Loader。
学习一下,以后看要不要用在项目上。
回复

使用道具 举报

3

主题

41

回帖

50

积分

初级会员

积分
50
发表于 2021-12-7 11:57:03 | 显示全部楼层
WZH 发表于 2021-12-6 23:59
在F1和F4上可能会有一点儿差别,动态加载会稍慢点,我这里只有H7的板子,没做测试。
在H7里,由于有Icah ...

楼主设个Github仓库吧。
回复

使用道具 举报

39

主题

926

回帖

1048

积分

至尊会员

积分
1048
发表于 2021-12-7 14:39:47 | 显示全部楼层
楼主牛,赞一个。
回复

使用道具 举报

0

主题

10

回帖

10

积分

新手上路

积分
10
发表于 2021-12-8 09:14:04 | 显示全部楼层
WZH 发表于 2021-12-6 17:22
差不多是这个意思。主机通过elf文件,把文件里程序的机器码回复出来,然后执行。与lua相比,空间资源要小 ...

你现在是怎么把 elf文件传递给主机的?
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-8 10:42:52 来自手机 | 显示全部楼层
252514251 发表于 2021-12-6 15:30
elf文件太大,能做成类似bin不

我后面又看了下链接器的命令行选项,通过命令行--nodebug --no-commment 可以把elf文件压缩的很小,基本上只保留了必要的信息。不知道是否满足你的要求
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-8 10:43:50 来自手机 | 显示全部楼层
----- 发表于 2021-12-7 11:24
我们这之前用Keil的Overlay实现过不同Code占用相同RAM,楼主这个更彻底,即是ROPI也是RWPI,并且自己写了EL ...

overlay也是一种很好的方法。
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-8 10:46:13 来自手机 | 显示全部楼层
nicole088 发表于 2021-12-8 09:14
你现在是怎么把 elf文件传递给主机的?

我现在用32的USB把sd卡虚拟成U盘,直接复制粘贴进去的
回复

使用道具 举报

12

主题

152

回帖

203

积分

高级会员

积分
203
 楼主| 发表于 2021-12-8 10:47:43 来自手机 | 显示全部楼层
jasondong388 发表于 2021-12-7 11:57
楼主设个Github仓库吧。

现在正在整理代码结构和注释,整理好后就开个git仓库
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-3-29 18:33 , Processed in 0.316968 second(s), 31 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表