romStart代码的小记

断断续续地在网上搜了很多很多资料,实在看不懂vxworks的romStart当中从rom搬移到ram的代码过程,其实也就一句代码,不过因为牵扯到重定位,所以其实从一接触到vxworks的启动时,就一直没有看懂过romStart代码的小记

 温故可以知新,这话不错,读代码百遍其义自现romStart代码的小记

 虽然我不知道我的理解对不对,但是还是要记录一下,以作参考

    ((FUNCPTR)ROM_OFFSET(copyLongs)) (ROM_TEXT_ADRS, (UINT)romInit,ROM_COPY_SIZE / sizeof(long));

这段代码其实就是代码的搬移过程。

 不知道网上为什么没有说,是我没有搜到,还是大家的起点都比较高,没有找到对这段代码的理解过程

 这段代码的目的是调用copyLongs这个函数(原型是:LOCAL void copyLongs (FAST UINT *source, FAST UINT *destination, UINT nlongs);),将代码从ROM拷贝到RAM

 从调用开始我就没看懂,或者说一知半解,因为代码没有直接调用copyLongs,而是对copyLongs使用了一个宏,如下定义:

 #define ROM_OFFSET(adr) (((UINT)adr - (UINT)romInit) + ROM_TEXT_ADRS)

 这个宏的意思,其实就是重定位了copyLongs在rom当中的位置,为什么要重定位呢?还得从开发板的启动和boot(非vxworks image,对于我今天说的重定位,其实没有区别)的位置开始说起.开发板启动时执行的第一条指令是在rom的开始地址的指令,所以代码必须放在这里开始启动,而boot位置自然而然就该在这里,但是!

 我们在链接的时候其实已经指明了代码应该放的地址,来看看链接时的参数,找了几个我认为关键的:

 ldarm是链接程序

 -Ttext 33e00000 这个参数指明了text段应该放在的起始地址,即一般所说的运行时地址。也就是说,代码都应该以这个地址为base,而置于此地址的第一个函数romInit(),链接器理所当然地认为它的地址是0x033e00000,copyLongs就在这个地址之上,离着romInit有着copyLongs-romInit的距离,这个不难理解。0x33e00000这个地址其实在源文件和makefile里面被当作地址赋于了RAM_HIGH_ADRS(RAM_HIGH_ADRS = 33e00000 # RAM text/data address)

 这是我们站在链接的角度来思考的地址,想像一下自己就是链接器,我要完成链接,产生可执行程序,需要哪些要知道的东西,比如由-Ttext指定的入口地址。在后面的参数里面还有一个脚本文件

  -T C:\Tornado2.2\target/h/tool/gnu/ldscripts/link.RAM

 因为这个文件夹里面还有Link.ROM的脚本,从这里我们也可以知道程度是以ram地址为准的.

 所以我们现在知道了需要重定位的矛盾点就在于,链接时的地址与运行时的地址不一致造成的,不然没事重定什么位啊,自己给自己找麻烦

 再说回到运行时,我们将boot强制放在ROM的起始地址处,其实是为了一开始运行就执行到指令,但是对于调用函数,因为函数地址是以ram为准的,也就是以33e00000为准,所以必须计算被强制放到rom后它的绝对地址是多少。于是有了宏ROM_OFFSET(adr)

  分析一下它的宏定义:(((UINT)adr - (UINT)romInit) + ROM_TEXT_ADRS

  我们知道了romInit的地址是0x33e00000,这是链接时的地址,链接器这样认为的!romStart代码的小记

  但实际运行是在ROM_TEXT_ADRS,这样的话,后面的所有函数地址其实都该以ROM_TEXT_ADRS为准了

  打个比方,火车头和火车第8节车厢(简称小8)的距离是有8个车厢的距离,当火车头停在广州站站牌的位置时,那小8的位置就是在离广州站站牌8个车厢的位置;后来火车开往了成都到达了成都站,火车头位于成都站站牌的位置,那小8的位置就是在离成都站站牌8个车厢的位置

  说白了就是简单的相对值和绝对值的问题

  话说回来,为了计算copyLongs在rom当中的位置,那就用它离romInit的相对距离加上romInit现在的地址。romInit被强制放在了ROM_TEXT_ADRS,所以出来了,copyLongs的实际位置就是

copyLongs - romInit + ROM_TEXT_ADRS,这个宏的意思就在于此。理解了这个宏,自然也就理解了后面的copyLongs后面的参数了.

    copyLongs的参数为source ,destination,nlongs,就是把source地址开始的nlongs长的代码数据拷贝到destination的位置,放到这里的实际调用中来看:

  ((FUNCPTR)ROM_OFFSET(copyLongs)) (ROM_TEXT_ADRS, (UINT)romInit,ROM_COPY_SIZE / sizeof(long));

  就是将ROM_TEXT_ADRS处开始,ROM_COPY_SIZE个字节长度的代码,拷贝到romInit处

  咦?romStart代码的小记拷贝到romInit?

    romInit不是在ROM_TEXT_ADRS的地方吗?那不是原地没动?!

 嗯!romStart代码的小记我当时也是这样认为的,所以觉得是段可有可无的代码,或者是其他情况下使用的。

 错!这里的romInit是一个符号,代表是这个函数的地址,这个地址是谁确定的?什么时候确定的?是你?是我?romStart代码的小记都不是,是链接器确定的,也就是说,在形成了可执行程序的时候,这个符号代表的地址就已经确定下来了,在这里就是前面提到的0x33e00000这个地址

 好了,明白了,这段代码果然是将代码从rom拷贝到了ram处romStart代码的小记

 既然这样,我们就可以明白了,这段代码执行之后,函数的调用就可以不用ROM_OFFSET宏了,因为代码已经到了链接器认为它应该在的位置,那么里面由链接器确定的地址当然可以直接使用了,over!

参考文档

http://blog.sina.com.cn/s/blog_9b47c4a8010114ie.html

posted @ 2018-08-22 07:49  jasonactions  阅读(408)  评论(0)    收藏  举报