1. romimage是什么?
romimage是wince编译过程中最后一步。在此之前,ce的编译系统已经调用自己的arm编译器,对每个模块完成了编译工作,并生成了.exe,.dll等文件;同时针对当前的环境设置,生成了.bib,.reg等文件。另外还有一些别的文件。最后编译系统将所有这些需要“打包”的文件,拷贝到_WINCEROOT/release目录下。而romimage的作用,就是根据ce.bib文件,来生成最后的nk.bin和nk.nb0。
2. romimage的输入和输出。
romimage输入ce.bib文件,输出nk.bin和nk.nb0。ce.bib相当于一个配置文件,告诉romimage如何生成映像。而nk.bin和nk.nb0实质上其实是一个东西,nk.nb0是系统在ram里跑的一个平坦映像(plane image)。当eboot或者ipl将nk.nb0加载(或者先将nk.bin“解码“然后加载)到指定的内存地址后,会跳转到这个地址上从而开始ce的os的执行。
而nk.bin是以sections为单位的映像。romimage其实最先生成的是nk.bin,然后将其组织成nk.nb0。关于bin文件的结构,在ce的文档里有一篇文章“Windows CE Binary Image Data Format”专门加以说明。
3. 准备工作。
为了便于调试追踪,我重新编译了romimage.exe,编译环境是vc6.0 sp6。编译的时候有些lib文件ms没有提供,将相关的代码注释掉即可,并不影响对romimage的理解。
另外由于romimage的运行时间太久,所以我处理了ce.bib文件,保留MEMORY、CONFIG段不变,MODULES段保留如下内容:
nk.exe g:/WINCE500/release/kernkitl.exe NK SH
osaxst0.dll g:/WINCE500/release/osaxst0.dll NK SHK
hd.dll g:/WINCE500/release/hd.dll NK SHK
coredll.dll g:/WINCE500/release/coredll.dll NK SH
filesys.exe g:/WINCE500/release/filesys.exe NK SHM
gwes.exe g:/WINCE500/release/gwes.exe NK SHM
device.exe g:/WINCE500/release/device.exe NK SHM
devmgr.dll g:/WINCE500/release/devmgr.dll NK SHM
这8个文件基本覆盖了MODULES段的各种情况。对于FILES段,类似的保留4个文件:
ceconfig.h g:/WINCE500/release/ceconfig.h NK
wince.nls g:/WINCE500/release/wince.nls NK SHU
initobj.dat g:/WINCE500/release/initobj.dat NK SH
boot.hv g:/WINCE500/release/boot.hv NK SH
另外对于ROMSIZE,设得越小越好,我改成了00300000。 这样在我的机器上,运行debug模式的romimage,只需要10秒钟,生成的nk.bin只有2M大小。
还可以进一步减少这个时间。一开始我的memory段是这样设的:
ARGS 80060000 00001000 RESERVED
NK 800B0000 02000000 RAMIMAGE
RAM 820B0000 01F10000 RAM
IMCPY 83FC0000 00040000 RESERVED
而AUTOSIZE=ON。这意味着romimage要对MODULES段和FILES段的所有的文件扫描两遍,第一遍的目的仅仅是确定真正的RAMIMAGE的大小。所以我直接设置RAMIMAGE的大小,将AUTOSIZE=OFF。现在memory段是这样的:
ARGS 80060000 00001000 RESERVED
NK 800B0000 223F10 RAMIMAGE
RAM 802E0000 3CE0000 RAM
IMCPY 83FC0000 00040000 RESERVED
这样运行romimage只需要5秒钟。但是这样做的目的不是节省这5秒钟的时间,而是对于romimage的整个过程更加简洁便于理解。
另外,对于windows mobile尤其漫长的编译时间感到厌烦的朋友,可以使用这种方法减少一些编译时间。
4. romimage的流程概述。
romimage做了一些初始化工作后,首先要做fixup。这也是romimage的主要工作。fixup的目的是根据rel文件给出的地址信息,将大部分modules里的地址信息reloacate。这是因为.exe和.dll文件本来是以进程的虚拟地址空间编译的,其base地址和加载地址可能并不符合realaddress的需要。fixup又分三种情况。第一种是对于内核空间的modules,比如nk, osaxst0.dll, hd.dll等,其base地址是在内核空间0x80000000以上,其fixup需要特殊处理。第二种是对于dll,其优先的加载地址是在slot1,但是其可写的数据段地址还要加载在slot0;第三种是虚拟地址slot0加载的.exe,这种一般不需要fixup。
之后对于有导入段的模块需要处理导入符号,有压缩标志的段进行压缩,还有一些其它的处理。
接下来需要对每个模块的段的位置加以调整。wince原则上将readonly段按照模块顺序依次以page大小对齐从NK开始放置。每个段之间会有一些闲置的区域,叫做holes,最后一个段到NK的结束地址还有一个很大的hole。wince利用这些holes存放readwrite段,还有其它的信息,比如e32, o32, romhdr, 模块和文件名称等等信息。因为对于readwrite段,要么会在系统初始化的时候被copy到ram区域(此种情况对应内核空间的readwrite段),要么会在程序初始化的时候给其分配具体的地址空间(此种情况对应普通的exe的readwrite段)。
最后将所有信息写入bin或者nb0文件,例如ptoc等各种信息,包括上面的e32等,还有具体的段的内容就是在这时写入的。
5. 总结。
romimage是一个挺有意思的工具。充分理解它的机制,对于理解wince的os,以及缩短具体项目的编译时间,是很有帮助的。我花了一段时间读懂了代码,但是由于工作紧张实在没有时间具体记录下来,只能写个大概了。所以我将3. 准备工作写得很详细,是希望能够方便有兴趣的朋友去研究。
http://hi.baidu.com/garnetttt/blog/item/c971bc31f45099ac5edf0eed.html