找回密码
 立即注册
Qt开源社区 门户 查看内容

嵌入式软件开发瞎折腾之“程序入口”那些事!

2019-5-17 05:31| 发布者: admin| 查看: 1280| 评论: 0

摘要: 由于平时工作很忙了,本打算一箩筐多写点,但是时间和精力不允许了。所以每次只能针对一个问题和爱好者们共同学习。今天讨论的是,嵌软的入口到底是谁,这里我们先来说下底层,底层懂了,用户态的也就出来了。针对一 ...
由于平时工作很忙了,本打算一箩筐多写点,但是时间和精力不允许了。所以每次只能针对一个问题和爱好者们共同学习。

今天讨论的是,嵌软的入口到底是谁,这里我们先来说下底层,底层懂了,用户态的也就出来了。针对一个处理器的底层开发来说,不管是arm裸机,还是linux系统引导程序像uboot之类的,或者是单片机,第一个运行的程序都不可能是main函数(包括顶层的应用程序)。为什么呢?我们来想一想,调用一个函数,需要把cpu本身的寄存器值保存在栈中,这样当被调函数返回时才不会干扰到主调函数。所以最基本的在C程序运行之前要先设置堆栈、设置好main函数返回的位置(也就是cpu中lr寄存器的值),除了这些还有别的吗?当然有,除了堆栈要设置之外,防止中断干扰程序运行,首先要关闭中断;为了防止看门狗引起的复位,要关闭看门狗;为了中断的正常响应,我们要设置好异常向量表;防止地址访问异常,我们还要关闭MMU;为了防止刚上电cache里面的数据还没有从内存中更新过来而引起的异常,我们要关闭cache。当然了,有些处理器不一样,要做的不仅仅这么多,我就简单写了上面的几个。

总而言之,嵌入式开发中,main函数一定不是一个可执行程序最先执行的地方。这就是我们所说的需要一个启动代码干的话,启动代码是汇编写的,在硬件初始化和异常向量表等建立完后,就可以调用main函数,进入C程序了。

既然main函数和普通的函数没什么区别,谁跳转执行它?是启动代码运行到一定阶段时引用的,那么main函数我可以任意取个名字吗?只要启动代码对应改成一致就可以了。不信的话,你可以试试,编译绝对没有问题。

以上所说的是指底层开发,有的哥们可能会说了,我在虚拟机上用gcc编译一个运行在ubuntu虚拟机上的程序为什么就必须用main函数呢?这个问题说明你还没有看懂我上面写的内容,在虚拟机上用gcc编译的运行在ubuntu虚拟机上的程序不属于底层范畴,那玩意是应用程序,编译裸机的编译链,因为是“裸”,所以那肯定是没有库的。启动代码和链接脚本都是自己开发,包括库。但是应用程序,你不可能像开发裸机那样写启动代码,为什么呢?你想想看,如果你上来启动代码里面关中断,又关看门狗,那么linux内核不死才怪!!所以说编译应用程序的编译链不需要开发者写启动代码,编译链本身自带一个启动代码和链接脚本(非裸机的启动代码),因为他们是运行在虚拟地址上,通过页表映射到物理内存,所以不同应用程序启动代码和链接脚本可以都用一个,至于为什么应用程序必须有main函数,那是因为编译链自身的启动代码跳转C函数的时候已经明明白白的写死了,就是main。所以,你懂得!启动代码将会和你自己开发的程序一起编译到你的可执行程序里面的。

另外,附加一个很简单的启动代码。



总结:嵌入式开发中,第一个可执行程序的入口一定不是“main”函数。入口地址取决于链接脚本,启动代码,makefile共同决定(嵌入式系统最先运行的地址取决于系统本身, 和可执行程序的运行入口不能混为一谈)。我一般遇到的比较常见的是entry指定的(还有别的方式)。另外,“main”函数和普通函数没有什么区别,没有那么嚣张!

----------------------------------------------------------------------------------------------------------------------
我们尊重原创,也注重分享,文章来源于微信公众号:后邵竹园,建议关注公众号查看原文。如若侵权请联系qter@qter.org。
----------------------------------------------------------------------------------------------------------------------

鲜花

握手

雷人

路过

鸡蛋

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了