<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Computer, Electron and Technology &#187; 嵌入式</title>
	<atom:link href="http://www.donevii.com/post/tag/%e5%b5%8c%e5%85%a5%e5%bc%8f/feed" rel="self" type="application/rss+xml" />
	<link>http://www.donevii.com</link>
	<description>DoneVII CET &#38; CPPLITE</description>
	<lastBuildDate>Wed, 02 Jun 2010 10:45:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>[转] 嵌入式单地址空间中实现动态加载的过程</title>
		<link>http://www.donevii.com/post/479.html</link>
		<comments>http://www.donevii.com/post/479.html#comments</comments>
		<pubDate>Wed, 10 Sep 2008 16:42:23 +0000</pubDate>
		<dc:creator>gavinkwoe</dc:creator>
				<category><![CDATA[mobile]]></category>
		<category><![CDATA[mtk]]></category>
		<category><![CDATA[arm]]></category>
		<category><![CDATA[nucleus]]></category>
		<category><![CDATA[动态加载]]></category>
		<category><![CDATA[嵌入式]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=479</guid>
		<description><![CDATA[转至：http://blog.csdn.net/pengzhenwanli/archive/2008/04/23/2319412.aspx#875603 之前有一篇文章是关于嵌入式单地址空间实现动态加载的想法，里面描述的是我根据相关资料进行猜测的地方，以及从技术上来说... ]]></description>
			<content:encoded><![CDATA[<p>转至：<a href="http://blog.csdn.net/pengzhenwanli/archive/2008/04/23/2319412.aspx#875603">http://blog.csdn.net/pengzhenwanli/archive/2008/04/23/2319412.aspx#875603</a></p>
<p class="MsoNormal"><span>之前有一篇文章是关于嵌入式单地址空间实现动态加载的想法，里面描述的是我根据相关资料进行猜测的地方，以及从技术上来说，可能需要的技术，最近难得有空闲时间，我实现了一下动态加载的。目前已经成功实现，下面说一下实现的过程。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span>先说一下实现此技术需要的平台：</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';">OS</span></span><span>：</span><span lang="EN-US"><span style="font-family: 'Times New Roman';"><a href="http://www.donevii.com/post/tag/nucleus" class="st_tag internal_tag" rel="tag" title="Posts tagged with nucleus">Nucleus</a></span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';">CPU</span></span><span>：</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">ARM7+cache</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';">Baseband</span></span><span>：</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">VT3406</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';">ADS1.2</span></span></p>
<p class="MsoNormal"><span>说一下这些东西的来历，</span><span lang="EN-US"><span style="font-family: 'Times New Roman';"><a href="http://www.donevii.com/post/tag/nucleus" class="st_tag internal_tag" rel="tag" title="Posts tagged with nucleus">Nucleus</a></span></span><span>是实时嵌入式单地址空间操作系统，</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">CPU</span></span><span>是介于</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">ARM7</span></span><span>与</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">ARM9</span></span><span>之间的</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">CPU</span></span><span>，</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">BB</span></span><span>芯片是</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">VIA</span></span><span>出的，这些东西目前都已经收掉不再使用，我也正好离职，从而有时间去实现一下动态加载的问题。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span>从理论上来说，动态加载很简单，只需要把当前的</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">PC</span></span><span>指针指向下一句执行的语句即可。也就是使用如下的</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">ASM</span></span><span>就可以实现：</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';">MOV PC, Address</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>这样就可以顺利执行程序，在我实现的时候，考虑如下问题，程序执行如何返回，参数如何传递，程序执行完毕返回到哪里。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>这些问题的解决，看起来比较复杂，其实很简单，程序的返回是放在</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LR</span></span><span>中，这样在上一个函数调用的时候，只要</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LR</span></span><span>的值不变，这样可以在下一个函数调用的时候，同样使用</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LR</span></span><span>，这样就可以顺利返回。关于参数传递，由于</span><span lang="EN-US"><span style="font-family: 'Times New Roman';"><a href="http://www.donevii.com/post/tag/arm" class="st_tag internal_tag" rel="tag" title="Posts tagged with arm">ARM</a></span></span><span>中使用</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">r0-r3</span></span><span>传递参数，这样只要不更改</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">r0-r3</span></span><span>，就可以顺利传递参数。这个地方想明白，我用了好久，特别是返回地址的问题，程序如何执行，应该返回哪里。解决方法如下</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>实现</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">DynamicLoader(UINT8 *pAddress)</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';">MOV PC, R0</span></span></p>
<p class="MsoNormal"><span>这个地方一定要用</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">ASM</span></span><span>实现，否则无法完成需要的功能。由于在调用此函数时，已经把函数的返回地址放到</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LR</span></span><span>中，具体</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">ASM</span></span><span>如下：</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';">MOV r0,address</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';">BL DynamicLoader</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>由于</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">DynamicLoaer</span></span><span>的实现问题，没有实际的返回，也就是不需要使用</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';">BX lr</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>这样来做为函数的返回。这是由于</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">R0</span></span><span>所指向的一个函数的开始地址，从</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">DynamicLoader</span></span><span>开始，其实执行的是另一个函数，这里的</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">DynamicLoader</span></span><span>只是起到了一个跳转的作用。但是又必须使用函数调用的方式来进行，而不能直接跳转，否则函数没有办法返回。由于</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">BL</span></span><span>的时候填充了</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LR</span></span><span>，这样在下一个由于实际调用不是使用的</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">B</span></span><span>指令，因为并没有设置</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LR</span></span><span>，这样仍旧是在调用</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">DynamicLoader</span></span><span>时的</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LR</span></span><span>，因此可以正确返回。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>函数可以正确调用并返回，这是程序很大的一个进步，这样就可以实际构造可以运行的程序了。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>下面说一下</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">ADS</span></span><span>编译为二进制可执行文件的问题，使用编译器如果一开始把所有的数据都放好，这样包括全局变量和静态变量，以及函数的执行地址等，都已在</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LINK</span></span><span>的时候根据指定规则确定实际的运行地址，也就是说所有的函数的实际运行地址在</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LINK</span></span><span>的时候已经确定。这样对于动态运行来说是不可行的，因为既然要动态加载，就需要所有地址都是静态的，因为每次对于读入内存的数据，起始地址是不缺定的，因此不能再</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LINK</span></span><span>时把所有的地址固定死。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>解决这个问题有两种方式，一种是在</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">scatter loader</span></span><span>中把程序的可执行地址固定好，在</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LINK</span></span><span>时不</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LINK</span></span><span>实际的数据，而在系统启动的时候，把这部分可执行文件拷贝的固定的地址，这样可以作为一个整体运行。但是这种方式由问题，就是应用的大小什么的都是固定死的，不能太灵活，不能根据应用实际调整。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>这里使用另外一种方式，选择程序不在</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LINK</span></span><span>的时候把所有的地址固定死，而是使用相对独立的函数调用方式。如下：</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>原来的方式可能使这这样</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';"><span>       </span>BL 0&#215;10008;</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>而使用相对的地址程序如下：</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';"><span>       </span>ADD r5,pc,#18</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';"><span>       </span>BL r5</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>这样虽然多了一句，但是可以做到函数的运行地址是动态指定的，而不是编译为固定的地址。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>其实</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">ADS</span></span><span>提供了把函数编译为独立地址的方式，</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';"><span>       </span>COMPILER</span></span><span>使用如下的参数</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">/ropi/rwpi</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';"><span>       </span>LINK</span></span><span>使用如下的参数</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">-rwpi –ropi</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>就可以把编译的程序做到运行时地址是独立的。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>从上面来开，编译时地址的问题，还有运行时加载的问题，都已经顺利解决。但是这里还有一个问题，就是如何确保动态应用如何每次在使用的时候，都从固定的入口进入的问题。也就是说，虽然有了内存中的运行地址，但是如何保证每次都从固定的函数开始执行呢？如果每次都从编译的可执行文件</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">0</span></span><span>地址开始执行，没有办法保证每次调用的是同一个函数。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>这个可以通过</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LINK</span></span><span>来保证每次是同一个函数在</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">0</span></span><span>地址，使用如下的参数</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span style="font-family: 'Times New Roman';">-first DyanmicAppEntry</span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>这样就可以保证</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">DyanmicAppEntry</span></span><span>的入口地址为可执行文件的开始了。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>上面的文章解决了动态编译和加载的问题，下面说一下动态应用的问题。如果要使一个应用有价值，比然需要提供本地的功能调用，而且对于手机来说，系统已经基本上实现了大多数的功能，如果在动态应用中再重复实现一些功能，可以说既浪费了空间，又浪费了时间。而且对于硬件相关的功能，必须通过本地调用来进行，这样就需要如何把本地调用传入动态应用中。如上文所说，本地的调用地址都是在</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">LINK</span></span><span>的时候确定的没有办法直接在动态应用中使用，这样需要在运行时把本地调用传入动态应用，由于动态应用的入口还有好几个参数可以使用，这样就可以构造一张系统调用的表，在运行的时候传入动态应用，这样可以通过表来调用系统功能，这样就解决了系统本地调用的问题。</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"><span><span style="font-family: 'Times New Roman';">       </span></span></span><span>这里要特别说一下安全的问题，由于动态应用是直接更改</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">PC</span></span><span>指针运行的，这样，如果应用出错，系统可能就</span><span lang="EN-US"><span style="font-family: 'Times New Roman';">CRASH</span></span><span>了，无法再继续运行，而且由于可以调用本地系统调用，可能做许多意想不到的功能，这样就可以在系统调用的时候</span><span lang="EN-US"></span></p>
<p class="MsoNormal"><span>增加一个中间层，一些核心功能，必须满足一定的权限在可以调用。</span></p>

	<h4>相关文章</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.donevii.com/post/477.html" title="[转] 在嵌入式单地址空间OS中实现动态加载的问题 (2008-09-11)">[转] 在嵌入式单地址空间OS中实现动态加载的问题</a> (0)</li>
	<li><a href="http://www.donevii.com/post/475.html" title="[转] 嵌入式系统中的模块动态加载技术 (2008-09-11)">[转] 嵌入式系统中的模块动态加载技术</a> (0)</li>
	<li><a href="http://www.donevii.com/post/481.html" title="[转] 实现动态加载VXWORKS .O/.OUT模块 (2008-09-11)">[转] 实现动态加载VXWORKS .O/.OUT模块</a> (1)</li>
	<li><a href="http://www.donevii.com/post/638.html" title="RO段、RW段和ZI段 (2008-11-28)">RO段、RW段和ZI段</a> (2)</li>
	<li><a href="http://www.donevii.com/post/568.html" title="山寨机教父蔡明介:联发科10年迅速崛起的秘诀 (2008-10-15)">山寨机教父蔡明介:联发科10年迅速崛起的秘诀</a> (0)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/479.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[转] 在嵌入式单地址空间OS中实现动态加载的问题</title>
		<link>http://www.donevii.com/post/477.html</link>
		<comments>http://www.donevii.com/post/477.html#comments</comments>
		<pubDate>Wed, 10 Sep 2008 16:37:41 +0000</pubDate>
		<dc:creator>gavinkwoe</dc:creator>
				<category><![CDATA[mobile]]></category>
		<category><![CDATA[mtk]]></category>
		<category><![CDATA[arm]]></category>
		<category><![CDATA[dynamic load]]></category>
		<category><![CDATA[动态加载]]></category>
		<category><![CDATA[嵌入式]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=477</guid>
		<description><![CDATA[转至：http://blog.csdn.net/pengzhenwanli/archive/2007/02/26/1514689.aspx 本文的的主要想法是来源于手持设备可运行应用程序和如何实现智能机问题的思考。问题的主要来源是关于可扩充应用程序的考虑，目... ]]></description>
			<content:encoded><![CDATA[<p align="left">转至：<a href="http://blog.csdn.net/pengzhenwanli/archive/2007/02/26/1514689.aspx">http://blog.csdn.net/pengzhenwanli/archive/2007/02/26/1514689.aspx</a></p>
<p align="left"><span style="font-size: small;">本文的的主要想法是来源于手持设备可运行应用程序和如何实现智能机问题的思考。问题的主要来源是关于可扩充应用程序的考虑，目前大部分手机都是非智能机，也就是不能扩充应用程序</span></p>
<p align="left"><span style="font-size: small;">1.智能手机与非智能手机<br />
        一般来说，智能手机目前公认三大系统，Windows Mobile，Linux和Symbian，也即是说采用这三种系统的手机，都成为智能机。我认为，从技术上来讲，智能机最主要的特征就是第一可扩充应用程序，也就是说用户可以自行安装需要的程序而不局限于手机自带的，第二就是多用户任务，也就是用户具有同时运行多个应用程序的权力。而非智能手机的操作系统可以说是五花八门，什么都有。但是基本上都有一个核心的特征，就是同时只能运行一个应用程序，而且所有的应用程序都运行在相同的地址空间，而智能机是运行在独立地址空间。一般来说，非智能机也支持多任务，不同的是这些任务共用相同的地址空间。用户操作的UI就是一个单独的任务，用户所能使用的功能基本上就是由UI提供的。<br />
        我原来对于非智能机是非常的不屑，认为没有什么发展前途，但是我最近又弄了一个非智能机的手机用了一下，发现很多功能都非常的人性化，从使用上来讲，并不亚于智能机，由此引发了我对于非智机功能的思考。对于智能机来讲可扩充的应用程序一般来说，都是由第三方开发商开发的，稳定性都有所缺陷，并不如原生的系统应用程序稳定。而且有些比较好的用程序价格不菲，我见过使用智能机的人大部分都是使用破解的应用程序，我本人也是。这个行为是违法的，当市场成熟以后，比如像美国，是不太可能的。</span></p>
<p align="left"><span style="font-size: small;">        智能机由于操作系统功能强大，一般要求系统的硬件性能强劲，这样相应的功耗也大，待机时间相应的缩短。非智能机可以运行在性能较差的硬件上，并且获得的UI表现，不弱于智能机。这样就可以在相同的电力消耗的情况下，获得更长的使用时间。<br />
2.非智能机获得智能机功能必须的要求<br />
        如上文所说，只要非智能机实现智能机最主要的两个特征即可获得智能机的功能。一个是用户自行安装应用程序的功能。另一个是同时运行多个应用程序的功能。<br />
3.用户自行安装应用程序的功能<br />
        除了智能机以外，目前有两种技术都实现了用户可自行安装应用程序的功能，一个是BREW另一个是Java ME(J2ME)。下面分别说一下这两种技术，BREW技术由Qualcomm（高通）创建，包括一整套的体系，从运营到分发都有。在本文里只是对于客户端技术的说明，对于BREW技术而言，已经非常符合本文中所提及的技术，本文从另一方面来讲，也可以说是分析了BREW的基本技术。BREW技术高通把持的非常严密，目前而言，并没</span><span style="font-size: small;">有开放源代码而且对于技术内部也是进行严密的封锁，因此目前出现的文章都是猜测技术的实现，但是对于技术来讲，万变不离其宗，要实现某种技术，有些东西是绕不开的，就像使用CDMA技术，无论是WCDMA，CDMA2000，还是TDS-CDMA都无法绕开CDMA的基本专利一样。BREW技术基本达到了本文的技术要求，既能动态加载，也能同时运行多个任务，而且对于系统功能的使用不像JavaME一样有严重的限制，基本上来说，可以使用系统提供的所有功能。而对JavaME，所提供的功能十分有限，就连存取本地文件都不可以。对于系统功能的使用，如果没有附加的支持，基本上不可能，目前应用最得的是游戏，最多有些网络方面的应用。对于提供系统级别的应用，比如说闹钟等，根本无能为力。也许以后能够提供，但是本人不太看好。另外还有一个就是Flash Lite技术，这个技术我并没有接触，就不详细说了。对于BREW和JavaME我都有相当长时间的接触，了解也比较细致，有些问题还是能够说一下的。<br />
        要解决用户可以自行安装应用程序的问题，必须解决以下几个问题，应用程序的加载运行问题，系统API的调用问题。<br />
3.1应用程序加载<br />
        对于嵌入系统来讲，与通常的Windows系统不一样，Windows的所用应用程序都在硬盘上，运行的时候根据需要加载到内存中，在运行，或者是使用虚拟内存技术，直接映射的硬盘也可以执行。而嵌入式系统通常是在ROM中，并不需要加载到内存才能运行，直接就可以运行，因此大部分的嵌入式系统都是统一做好一个系统的Image，然后放到ROM中运行。这样所有的地址都在编译期间确定，要是再动态加载应用程序，将会面临运行时地址确认的问题。一般而言，对于嵌入式系统，ROM使用Flash来代替，Flash中一部分作为ROM，另一部分作为嵌入式的文件系统，具体的系统格式这里不作考虑。要是可加载应用程序的话，一般来说是放在文件系统中。这样要运行可动态加载的应用程序，并不复杂，只要把应用程序调入内存中，运行时设置正确的寄存器就可以了。</span></p>
<p align="left"><span style="font-size: small;">这里也就是把可执行的文件加载到内存中，由于是单地址空间的，而不是像Windows一样每个应用程序都是独立的地址空间，这样应用程序可以从任意地址开始执行，这样载入内存以后，把当前的执行指针PC这为此内存地址即可。这也是单地址空间的程序可以执行的关键。</span></p>
<p align="left"><span style="font-size: small;">3.2系统API的提供</span></p>
<p align="left"><span style="font-size: small;"> 要提供可以运行时call的API，在单地址空间可加载应用程序的约束条件下，可以使用的方法也非常的单调。一般来说，单地址空间的应用程序是统一编译和链接的，这样生成可执行文件以后，所有的地址已经固定了，这样如</span><span style="font-size: small;">3.1所说，应用程序如果每个都调用相同的系统API，比如memset等，由于应用程序时独立加载的，这样由于在编译过程中已经把所有的地址确定，所以每个应用必须链接独立的lib，这样造成了空间浪费。如果只是单独的应用，不提供这一步，系统已经可以动态加载了。</span></p>
<p align="left"><span style="font-size: small;">但是目前是要求在嵌入式单地址空间实现，必须考虑空间的问题。因此必须解决系统库可以动态加载的问题。也就是库的地址不是在链接的时候确定。</span><span style="font-size: small;">只要能够解决编译时的链接问题，就可以做到。</span></p>
<p align="left"><span style="font-size: small;">关于<br />
4.同时运行多个应用程序的功能</span></p>

	<h4>相关文章</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.donevii.com/post/475.html" title="[转] 嵌入式系统中的模块动态加载技术 (2008-09-11)">[转] 嵌入式系统中的模块动态加载技术</a> (0)</li>
	<li><a href="http://www.donevii.com/post/479.html" title="[转] 嵌入式单地址空间中实现动态加载的过程 (2008-09-11)">[转] 嵌入式单地址空间中实现动态加载的过程</a> (0)</li>
	<li><a href="http://www.donevii.com/post/481.html" title="[转] 实现动态加载VXWORKS .O/.OUT模块 (2008-09-11)">[转] 实现动态加载VXWORKS .O/.OUT模块</a> (1)</li>
	<li><a href="http://www.donevii.com/post/638.html" title="RO段、RW段和ZI段 (2008-11-28)">RO段、RW段和ZI段</a> (2)</li>
	<li><a href="http://www.donevii.com/post/568.html" title="山寨机教父蔡明介:联发科10年迅速崛起的秘诀 (2008-10-15)">山寨机教父蔡明介:联发科10年迅速崛起的秘诀</a> (0)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/477.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[转] 嵌入式系统中的模块动态加载技术</title>
		<link>http://www.donevii.com/post/475.html</link>
		<comments>http://www.donevii.com/post/475.html#comments</comments>
		<pubDate>Wed, 10 Sep 2008 16:01:54 +0000</pubDate>
		<dc:creator>gavinkwoe</dc:creator>
				<category><![CDATA[mobile]]></category>
		<category><![CDATA[mtk]]></category>
		<category><![CDATA[arm]]></category>
		<category><![CDATA[dynamic load]]></category>
		<category><![CDATA[加载]]></category>
		<category><![CDATA[动态]]></category>
		<category><![CDATA[嵌入式]]></category>

		<guid isPermaLink="false">http://www.donevii.com/?p=475</guid>
		<description><![CDATA[摘要 提出一种适用于嵌入式系统的模块动态加载技术，设计实现简单，占用资源少，开销小，并且成功运用于DeltaOS．可提高系统的灵活性和扩属性.介招加载与动态链接的原理和应用情况，解... ]]></description>
			<content:encoded><![CDATA[<p><strong>摘要</strong></p>
<p>提出一种适用于嵌入式系统的模块动态加载技术，设计实现简单，占用资源少，开销小，并且成功运用于DeltaOS．可提高系统的灵活性和扩属性.介招加载与动态链接的原理和应用情况，解释相关术语，描述基本设计思路：详细说明该技术的核心。即模块声明、调用库、两级重定位表，最后给出结论。</p>
<p><strong>关键词</strong></p>
<p>模块 动态加栽 嵌入式系统DeltaOS</p>
<p><strong>引 言</strong></p>
<p>随着电子技术的飞速发展，嵌人式设备应用越来越广泛，复杂度也越来越高。这使得硬件和软件设计比例发生了很大变化，软件开发的比重越来越大。然而传统嵌入式开发过程中需要将应用与操作系统编译链接成一个整体，然后下载到目标机上运行。如果在调试过程中发现问题，需要重新编链接然后重复下载运行的过程。这样的开发流程周期长而且繁琐，已经越来越不适应快速市场化的需要。</p>
<p>为了适应多样化的嵌入式应用和加快嵌入式系统的开发过程，除了需要可靠的基础平台软件的支持，如带有文件系统、网络协议栈的RTOS和配套的集成开发环境，更重要的是需要可以动态扩展的系统平台。近年来，新一代的嵌入式操作系统已经开始使用动态扩展技术：将基本系统(包括操作系统以及其他共享功能调用库)和应用程序开发分开处理，支持模块更新和动态加载技术。很多主流的传统嵌入式操作系统厂商，如windRiver、Green HilIs、Lynxworks，都推出了面向航空航天、基础通信设备等领域的高可靠、高性能的RTOS版本，支持应用和系统组件的动态加载和更新；而在消费电子领域，相关的操作系统厂商，如symbian、Palm、Microsoft，更是积极推出了具有相应功能的操作系统，在新一代移动设备上得到了广泛应用。</p>
<p>为了成为可动态扩展系统平台，大部分嵌入式操作系统需要使用动态加载技术。总的来说，动态加载是指应用或者系统在运行过程中需要使用某模块的服务，于是通过一系列预定的动作将指定模块加载到系统中，让调用者继续顺利工作。它实现的关键就是加载与动态链接技术。因为加载和动态链接互相依赖，关系紧密，所以将两者放在一起进行讨论。</p>
<p><strong>1 加载与动态链接机制</strong></p>
<p>加载主要负责将模块程序从二级存储设备(比如硬盘或者Flash)搬移到指定内存空间，并且将模块交由系统加载器统一管理。</p>
<p>程序链接分为静态链接、加载时链接和运行时链接。静态链接就是将程序和它运行所需的全部库链接成一个执行文件。它的优点是可以独立运行、速度快，但是它链接生成的代码尺寸比较大。加载时链接是指程序在编译链接时不会把它用到的库链接到执行程序中，而是在它被加载器加载时才解析执行文件，依次把用到的库装载到系统中让其运行。它的优点是程序本身代码量减小，但运行时程序占的内存并没有减小，同时增加了加载器的工作量。动态链接是加载时链接的进一步发展，它是指将库的加载过程延迟到程序运行时执行。这种方式不会给程序引入额外的代码，也不会增加加载器的开销，只有当应用真正使用某库时才会加载该库，减少了不必要的空间占用。它的缺点是可能会有一些运行开销。</p>
<p>嵌入式系统中动态加载和普通的动态链接概念类似，但是嵌入式系统中的加载链接器有其自身的特点：它是交叉加载，主机端做一部分工作，比如程序的重定位，执行文件的解析等等；而目标机端相对简单，主要做模块搜索定位和空间分配，以及指定物理地址或者映射虚拟地址让其运行。一部分嵌入式系统不支持虚拟内存，应用和内核共享存储空间。当系统加载了多个应用到系统中时，一般需要使用overlap技术来解决内存空间有限的问题，即是当多个应用的运行地址空间冲突时，加载器会冻结当前暂时不运行的应用，让新加载的应用使用指定的地址空间，PairnOS中就采用了这样的设计。对于支持虚拟内存的嵌入式系统，加载器的工作被大大简化，每个应用都有可以运行在同样的虚拟的空间，不需要加载器为其重定位或使用overlap技术，因此提高了工作效率。Vxworks6．O，WinCE都使用了这种设计。两种方式在不同的领域都有比较多的应用。</p>
<p>文中提出的模块动态加载技术是基于支持MMU(Memory Management Unit)的32位嵌入式操作系统，采用了加载与动态链接技术。使用该技术构建的嵌人式系统面向高端市场，特别是对系统可靠性、安全性要求很高的领域。在DeltaOS新一代高可靠的版本HAR(High Available Reliable system)的研发过程中，即成功地实现了基于该设计的加载器LambdaLoader，达到了预期的性能要求。</p>
<p><strong>2 模块动态加载的设计</strong></p>
<p><strong>2.1 设计思路</strong></p>
<p>首先定义一些概念：模块、目标程序、接口函数地址表和调用库(call Library)。</p>
<p>①模块，主要是指加载器加载的一个单位，并且这里模块的概念主要是强调它是为应用或者系统提供一系列服务的提供者。</p>
<p>②目标程序，是指模块的使用者。它可以是应用，也可以是另一个模块。</p>
<p>③接口函数地址表(文中也称之为模块重定位表)，指在模块中有一个数组表，该数组表的内容是该模块对外提供的函数接口的地址。</p>
<p>④调用库，是供模块调用者链接使用的专有库。它与相关模块一一对应，将封装了的模块接口供目标程序使用。除此以外，它还有一个运行时才确定的模块重定位表地址指针和模块动态查找定位的代码。</p>
<p>如果在系统中要实现动态加载，首先需要一种模块定位机制，使得调用者能够在系统中动态定位需要的模块，其次是要能让模块与目标程序动态的关联在一起，协调工作。为了解决这些问题，需要一系列相关的设计：规定模块的声明方式；简化目标机端模块地址空间定位的工作；重定位表的机制等等。基于这样的设计，系统可以比较顺利地实现动态加载。模块动态加载的工作流程如图l所示。这里描述的主要是目标机端的工作。</p>
<p> </p>
<p><img src="http://www.oklinux.cn/upimg/070520/11O643LT5015242.jpg" alt="" /><strong>2.2 模块的声明</strong></p>
<p>模块首先要定义它的相关属性。这里使用模块声明文件来完成这个工作。模块声明文件中需要定义：模块名字、版本、对外提供的API接口。在系统编译模块程序后，会调用一系列的script代码。这些script会根据模块名字查找模块对应的模块声明文件，并根据该文件生成供模块调用者使用的调用库和与模块一起链接的附加库。</p>
<p>附加库包含系统后台通过调用script生成的接口函数地址表和模块注册函数。在每个模块的初始化函数中，会调用一个模块的注册函数(该函数主要工作是向系统注册模块的名字和接口函数地址表地址)。当模块被加载时，初始化函数会被系统调用，向系统注册模块信息，此后模块交由加载器统一管理。</p>
<p><strong>2.3 调用库</strong></p>
<p>每个模块在提供一个模块重定位表的同时，必须提供一个与之对应的模块调用库。别的目标程序必须并且只能通过调用库来使用这个模块提供的服务。每个调用库都有一个存储本模块重定位表的地址指针变量。该变量在模块被目标程序第一次使用时会被初始化为相应模块重定位表地址。</p>
<p>在模块第一次被目标程序使用即开始动态加载过程时，首先运行的是调用库的库初始化代码(Library initialcode)，它通过指定的系统调用来初始化库中的模块重定位表基地址指针。此后每次目标程序使用模块提供的函数接口时，都通过以下公式得到该接口的实际地址：模块接口实际地址=模块重定位表基地址+函数index×4</p>
<p>在该公式中，函数index是指对应函数在模块重定位表中的数组下标值。因为根据模块声明文件生成的调用库中已经包含了每个函数的索引信息(index)，同时在32位系统中需要乘以4得到准确的偏移量，所以当调用库中重定位表地址被初始化后，可以通过这样一个简单计算得到指定接口实际地址，完成函数调用。</p>
<p>当一个目标程序使用了模块，并正确动态加载后，其关系如图2所示。目标程序中链接了调用库，包含了函数跳转表和指向模块重定位表基地址的指针(ModuleBase)；模块中则链接了附加库，包含了函数接口地址表(模块重定位表)。调用模块函数时，经过动态加载模块的过程以后，目标程序的模块重定位表基址指针指向了对应模块的函数接口表，然后函数调用就可以顺利进行了。</p>
<p> </p>
<p><img src="http://www.oklinux.cn/upimg/070520/11O643L911023U7.jpg" alt="" /><br />
<strong>2.4 两级重定位表</strong></p>
<p>在嵌入式领域，为了降低性能开销和增加确定性，目标机端加载器不会做程序重定位，而将相关工作在主机端完成，所以目标机端加载的所有程序都是绝对定位后的程序．为了实现系统动态扩展，必须使各个模块能够单独链接生成执行程序，并且运行时不用关心彼此的定位，这样即使一个模块被动态替换后也能同其他程序一起协调运行。这里通过两级重定位表机制来完成这个协调性的工作。</p>
<p>对于内核、操作系统组件模块或提供服务给其他目标程序使用的模块，要维护一张本模块提供的接口函数地址表(即模块重定位表，这里称之为二级重定位表)。为了保证本模块的向后兼容性，模块必须保证其接口函数在模块重定位表中的相对位置固定。即使今后不能提供这个接口函数，也需要将其保留，以保证同以前版本的二进制兼容性。</p>
<p>在模块的初始化代码中，模块通过系统调用向加载器注册这个模块重定位表的地址，注册时需提供模块名和模块重定位表的地址。加载器中管理着一个称为一级重定向表的表格。这个表的表项是“模块名”到“模块重定位表地址”的映射。因为这只是一个映射关系，所以各个模块对应的表项在一级表中的具体位置是可以改变的。</p>
<p>二级重定位表如图3所示。</p>
<p> </p>
<p><img src="http://www.oklinux.cn/upimg/070520/11O643L9603F07.jpg" alt="" />使用两级重定位表的规则如下：</p>
<p>①模块可通过模块重定位表向其他目标程序提供接口函数；</p>
<p>②目标程序要使用别的模块提供的接口函数必须通过对应模块的调用库来实现；</p>
<p>③目标程序在使用别的模块提供的接口函数之前，必须通过加载器提供的系统调用服务获取对应模块重定位表来基地址初始化对方的调用库。</p>
<p><strong>结 语</strong></p>
<p>该设计实现了在嵌入式系统中的模块动态加载与更新，使得在嵌入式软件开发过程中，开发人员可以更有效的设计系统，共享资源，达到提高效率、产品快速市场化的目的。在基于DeltaOS的实现中，可以完成应用的任意加载卸载，系统组件的动态更新；多个应用可以共享一个全局的模块；一个应用可以同时使用多个模块等等。整个系统扩展性和灵活性大大提高，较好地满足了实际需要。但是设计中对容错性、健壮性的考虑还不够，在应用与模块的间接调用处理上还有优化的空间，所以在这些方面还需要进一步改进。</p>

	<h4>相关文章</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.donevii.com/post/477.html" title="[转] 在嵌入式单地址空间OS中实现动态加载的问题 (2008-09-11)">[转] 在嵌入式单地址空间OS中实现动态加载的问题</a> (0)</li>
	<li><a href="http://www.donevii.com/post/479.html" title="[转] 嵌入式单地址空间中实现动态加载的过程 (2008-09-11)">[转] 嵌入式单地址空间中实现动态加载的过程</a> (0)</li>
	<li><a href="http://www.donevii.com/post/638.html" title="RO段、RW段和ZI段 (2008-11-28)">RO段、RW段和ZI段</a> (2)</li>
	<li><a href="http://www.donevii.com/post/568.html" title="山寨机教父蔡明介:联发科10年迅速崛起的秘诀 (2008-10-15)">山寨机教父蔡明介:联发科10年迅速崛起的秘诀</a> (0)</li>
	<li><a href="http://www.donevii.com/post/325.html" title="字节对齐详解(x86 + ARM) (2007-05-18)">字节对齐详解(x86 + ARM)</a> (0)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.donevii.com/post/475.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
