找回密码
 立即注册
查看: 281|回复: 10

动态链接的设想

[复制链接]
已绑定手机

61

主题

410

回帖

1133

积分

金牌会员

积分
1133
发表于 2026-9-23 11:25:37 来自手机 | 显示全部楼层 |阅读模式
同样的功能,比如oled显示,flash读写,文件系统,bootloader里面有,用户程序里也要用,那放两份同样的代码很浪费空间啊。能不能获取bootloader里面的函数地址。写一个函数表(只有声明,以及其跳转地址),开发用户程序时候直接把函数表编译进去,使用时自动跳转到bootloader里面的对应函数来执行。
这样底层api我就可以都藏到bootloader里面充当“系统调用”,你开发你的用户程序,想操作硬件就走“系统调用”,既节省空间,又可以保证我的核心代码不泄露,还可以使用户程序完全和硬件无关(硬件操作都封装成APi运行时链接,换硬件只用换一套函数表即可),有尝试过的吗
回复

使用道具 举报 送花

已绑定手机

61

主题

410

回帖

1133

积分

金牌会员

积分
1133
 楼主| 发表于 2026-9-23 11:27:08 来自手机 | 显示全部楼层
更进一步,如果能写出来完全自包含的函数,把他编译到固定地址,是不是就可以被rtos当做任务函数直接挂载(这个有点抽象,而且自包含不是很现实,除非用一点tirck)
回复

使用道具 举报 送花

已绑定手机

61

主题

410

回帖

1133

积分

金牌会员

积分
1133
 楼主| 发表于 2026-9-23 11:29:26 来自手机 | 显示全部楼层
完全自包含不是很现实,你总得调用外部函数吧,你总得操作外设吧,这怎么搞?问题就在这了,如果你要用刚刚动态链接的思路,把外部调用以函数表的形式给出,加载器的rtos这边提供好所需的所有函数,那完全自包含不就很容易了,说不定还有戏,有想品鉴一下的吗
回复

使用道具 举报 送花

已绑定手机

61

主题

410

回帖

1133

积分

金牌会员

积分
1133
 楼主| 发表于 2026-9-23 11:40:50 来自手机 | 显示全部楼层
就是说bootloader加载跳转userapp了就拉回不来了,控制权全交出去了。如果能在bootloader里跑个抢占式rtos,userapp是一个完全自包含的函数。完全自包含是很严格的条件,本来很不实用几乎嘛也干不了,但是加载器提供给你了函数表,于是乎userapp可以使用“系统调用”的方式发挥功能。同时,如果划分多个app,并在“系统调用”的函数里塞个垫片劫持一下,就可以实现多任务同时发起一个调用时候的“锁”,感觉这样就很美妙了(已经开始幻想了?),这么搞有可行行吗
回复

使用道具 举报 送花

已绑定手机

61

主题

410

回帖

1133

积分

金牌会员

积分
1133
 楼主| 发表于 2026-9-23 11:46:44 来自手机 | 显示全部楼层
因为是待加载的完全自包含,并且系统调用肯定是你事先写好的不会有bug的代码(额,这个层面有💩那啥也别说了),所以还有个先天优势就是相比于普通rtos你没那么容易把系统写死,因为毕竟完全自包含这个限制下,你不能随便拉一个外部函数就来调,随便拉一块内存就访问(哦对,任务函数里想使用内存,要么函数里开数组吃任务栈,要么使用“系统调用”的malloc使用加载器里面的堆)
回复

使用道具 举报 送花

已绑定手机

61

主题

410

回帖

1133

积分

金牌会员

积分
1133
 楼主| 发表于 2026-9-23 11:54:18 来自手机 | 显示全部楼层
这么搞有什么问题吗,感觉这么搞就有比较贴近真正意义上的系统了,多任务,从外部装载任务,假装的系统调用(其实就是函数指针表)和所谓动态链接(其实本质还是静态链接,额,因为地址都已经定死了)
回复

使用道具 举报 送花

已绑定手机

232

主题

239

回帖

1302

积分

版主

积分
1302
发表于 2026-9-23 17:32:06 | 显示全部楼层

我已经把帖子内容和相关手册章节看完了。下面针对这位用户"动态链接/函数表/系统调用"的设想做技术解答。


关于"动态链接"设想的解答

先给结论:在 STC 单片机上,这个设想在原理上是成立的,而且 STC 官方手册本身就提供了最接近的工程实现范例("使用STC的IAP系列单片机开发自己的ISP程序")。但要真正做成"函数表 + 运行时跳转"的系统调用机制,需要你自己解决几个硬件层面绕不过去的约束。

一、原理层面:函数表跳转,在 51/C251 上完全可行

你设想的"只声明函数原型 + 跳转地址,编译进用户程序,运行时跳到 bootloader 里的实际函数",本质就是函数指针表。手册给出的官方范例就是这么做的:

#define ISPPROGRAM 0xfa00 //ISP下载程序入口地址
void (*IspProgram)() = ISPPROGRAM; //定义指针函数
……满足下载条件时调用 IspProgram();

这种方式把 ISP 模块的绝对入口地址 0xFA00 作为函数指针调用,是 STC 官方认可的用法。所以"用户程序通过固定地址调用驻留在另一段 Flash 里的函数"这件事没有原理障碍——因为 8051 的程序空间是统一编址的,只要函数被编译/链接到固定绝对地址,跳过去执行即可。

二、但有几个硬件层面的硬约束,必须正面解决

1. bootloader 必须是"可被调用的固定地址代码",且不能被擦掉

官方范例的 Flash 规划是:从 0000H 起 62.5K 给用户程序区,用户 ISP 区放在固定页(如 0xFA00),复位入口映射区固定。你的"函数表"里每个函数地址,都必须在链接阶段被固定到绝对地址,且这段区域要保证在升级用户程序时不被擦除覆盖。

2. 中断向量是最大的坑

用户程序运行时的中断(INT0、Timer0、UART……)入口地址是固定的(如手册列出的:INT0 在 FF:0003H、TIMER0 在 FF:000BH、UART 在 FF:0023H)。如果 bootloader 里也想用中断,就会出现"两套中断向量"的冲突。你的"系统调用"方案里,凡是会用到中断的外设(串口、定时器、ADC 中断等),都必须明确约定:中断由谁接管、向量如何映射。官方范例的做法是:ISP 代码自己接管串口中断完成握手,跳转到用户程序前把 SFR 恢复到复位值,把控制权完整交给用户程序——也就是说,官方是"分时独占",不是"并存共享"。

你想要"bootloader 跑 RTOS、userapp 当任务"的形态,就必须让 RTOS 接管全部中断向量,userapp 完全不能自己开中断,只能通过函数表请求服务。这在软件上是可设计的,但要写死规则。

3. "控制权交出去就拉不回来"的问题,你用软件复位可以部分解决

你担心的"跳转 userapp 后就回不来",手册提供了两个可控手段:

  • 软件复位:IAP_CONTR 的 SWBS 位

    • SWBS = 0:软件复位后从用户代码开始执行
    • SWBS = 1:软件复位后从系统 ISP 监控代码区开始执行
    • 配合 SWRST = 1 产生软件复位

    所以"从 userapp 回到 bootloader"是可以做到的(复位回去),但这是复位级的跳转,会丢失全部 RAM 上下文,不是普通函数返回。想做成"RTOS 调度 userapp 又随时收回",只能靠复位层面的往返,做不到真正意义上的"函数调用返回"。

  • IAP 方式改写程序区:IAP 可以对目标地址做字节读/写/扇区擦除(每扇区 512 字节),bootloader 可以用它来更新用户程序区。但注意:IAP 写只能 1→0,要 0→1 必须整扇区擦除,所以不能把它当成"运行时可随意修改的堆"。

4. 内存(堆)的问题

你设想"任务函数要么吃任务栈,要么走系统调用 malloc 用加载器里的堆"。这一点在 51 上是最难的:8051 的 RAM 空间小且分 xdata/idata 等类型,把"堆"放在 bootloader 里、再通过函数表给 userapp 用,跨段的指针传递和栈切换非常别扭。这在 STC32(C251,32 位寻址)上会现实一些,在纯 8 位 51 上收益很低、代价很高。

三、给你几条务实的建议

  1. 先做"函数表 + 绝对地址跳转"这一步,参考手册"使用STC的IAP系列单片机开发自己的ISP程序"范例的框架,把 API 表设计成结构体数组(函数指针),放在固定地址。这一步完全可行,能立刻实现"节省空间 + 隐藏核心代码"的目标。
  2. "bootloader 跑抢占式 RTOS + userapp 当自包含任务"要谨慎。你的自包含任务无法开中断、不能直接碰 SFR,全部功能要靠函数表——这就是把一个单片机系统硬做成一个"没有 MMU 的微内核"。理论可行,但在 51 这种资源上,你会花大量精力处理跨段指针、栈切换、中断独占,收益不一定对得起复杂度。若真要做这类实验,建议用 STC32G/STC32G144K246(C251,32 位) 平台,比 8 位 51 从容得多。
  3. 你帖子里自己也点破了关键:"本质还是静态链接,地址都已经定死了"。是的——因为 Flash 是只读的、地址在链接时确定,它永远是静态链接,只是你用函数表把它"伪装"成了动态链接。真正的动态链接需要重定位能力,51 没有。所以这个方案准确的叫法是:"固定地址系统调用表",而非动态链接。
  4. "函数表 + 垫片加锁"实现多任务互斥:这个思路是合理的,函数表里的每个入口套一层编号/信号量,就能做"系统调用级"的互斥,不依赖 userapp 自觉。这部分可以实现,属于软件设计范畴。

总结一句:你的方案核心(函数表固定地址跳转、API 隐藏、系统调用风格)在 STC 单片机上是可行且有官方范例支撑的;但"抢占式 RTOS + 完全自包含 userapp + 动态内存"这一层,受限于 51 的中断独占机制、复位级上下文丢失、小容量分段 RAM,理论可行、工程上性价比很低,除非换用 STC32(C251)平台。

如果你告诉我具体用的是哪颗芯片(型号),我可以帮你查该型号的 Flash 分区、EEPROM 可自定义大小、IAP 命令集和中断向量表,给你一份更具体的"函数表 + 固定地址"实现框架代码。


🔍 搜索 "动态链接 设想 STC 单片机"

📌 相关论坛讨论

  1. 金水32051编译器的安装与使用
  2. 系列文章目录--STC单片机 FreeRTOS入门
  3. 部分较难的贴可通知我:时钟树,PWM,DMA,CAN,电机控制 | 不要在本贴咨询

⏱️ 查找用时 7.3s | 总回答用时 16.6s

回复

使用道具 举报 送花

已绑定手机

123

主题

5133

回帖

1万

积分

超级版主

无情的代码机器

积分
11465
发表于 2026-9-23 17:33:46 | 显示全部楼层
关于“核心代码不泄露”:
用户区可以访问api区,意味着ROM能读出来。。。能读出来就能反编译了。


共用函数指针共用中断可参考这个:
一种USER_ISP和USER_APP共用中断方法
https://www.stcaimcu.com/thread-17200-1-1.html

三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

已绑定手机

2

主题

154

回帖

470

积分

中级会员

积分
470
发表于 2026-9-23 20:48:07 | 显示全部楼层
这个类似插件模型开发,或脚本模式。
插件模型:
  框架程序(isp/app)加载dll或其他形式的bin,传入一个缩主的结构指针,这个结构有各种函数指针和数据,供子模块调用。

脚本模式:
  实现一个脚本引擎,如lua/python,
  app或子模块是脚本,如lua脚本等,脚本可以调用宿主导出各接口。

框架程序或脚本引擎是缩主程序,提供生命周期管理,和提供各种基础功能,包括中断注册管理等,
回复

使用道具 举报 送花

已绑定手机

32

主题

446

回帖

2869

积分

金牌会员

积分
2869
发表于 2026-9-24 00:42:38 | 显示全部楼层
有想法,有些意思。
有时要实现的东西会被硬件限制住。
学习MCU
回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-11-8 02:47 , Processed in 0.076679 second(s), 78 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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