点击上方,选择“置顶/星标公众号”
大家好,我是麦鸽。
Linux中有很多编程思想可以学习,很多大佬把这些思想、机制运用到单片机的编程上,STM32 模拟Linux kernel自动初始化流程。
如果逻辑非常复杂,涉及的模块比较多,那么这种顺序执行的代码就会比较臃肿,各模块耦合非常紧密。Linux kernel 中,有各种外设驱动,想按照一个顺序逻辑执行下去,几乎是不可能的。
如何能实现这样的功能了,需要一些背景知识:
1,程序代码的组织
2,链接脚本相关的知识。
代码的组织,如图片需要知道变量a,b及函数指针 f,f2是存放在程序的哪些段中,可以去看一下这篇stm32 启动代码 实现|C语言,上述的a,f都是存放在bss 段中,b,f2是存放在data段中,因为已经给定了初始值,而实现这个intcall会把需要自动初始化的数据放到一个自定义的段中去,如.initcall。
当然这还不够,还需要告诉连接器(LD) 要把 .initcall 段也链接到程序中,所以也需要这段修改。
这段按8字节对齐,定义两个全局变量,及按0-5顺序的链接这些数据,这样的两处修改,再来看一下程序各段的情况。
已经多出红色框框为.initcalls段,这段总共是8个字节,从0x80005a8除开始。
和上面的size工具是匹配的,而绿色框框的地址就是SystemInit(0x08000231,小端模式。)
所以通过attribute及修改链接脚本,就把函数指针变量放到了.initcall 段中。
实现的这张图片,就是从.initcall段中取出函数地址,然后直接调用,非常容易把函数的地址及这个函数指针变量的地址搞混。
最后在来看一下initcall 段:
![]() | ![]() |
🫵兄弟们!一个人单打独斗确实能冲得挺快,但要想走得更远、更稳,还得靠一群志同道合的伙伴啊!
👊 麦鸽的知识星球现在已经聚集了一波人,大家都在这里互相学习、共同进步。
如果你也想找个靠谱的学习圈子
赶紧 戳链接 🔗 加入我们吧!
在这里,你能读到星球专栏的干货,优质教程,练手项目,随时向麦鸽提问,还能帮你定制学习计划。别犹豫了,兄弟,一起冲!💪
往期推荐
收到大厂发来的一块神秘板子,直接让我的万用表都慌了!小体积大功率的25A电源模块开箱
嵌入式C语言冷知识!枚举最后的"end"竟是这个作用
血泪警告,嵌入式开发者滥用全局变量的几个"致命陷阱",第3个坑过所有新人!
从编译下载到运行:STM32到底是如何通过程序控制硬件