<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><![CDATA[Decell.org - 嵌入式技术]]></title>
<link>http://www.decell.org/</link>
<description><![CDATA[心坚石也穿]]></description>
<language>zh-cn</language>
<copyright><![CDATA[Copyright 2005 PBlog2 v2.4]]></copyright>
<webMaster><![CDATA[decell@163.com(Decell)]]></webMaster>
<generator>PBlog2 v2.4</generator> 
<image>
	<title>Decell.org</title> 
	<url>http://www.decell.org/images/logos.gif</url> 
	<link>http://www.decell.org/</link> 
	<description>Decell.org</description> 
</image>

			<item>
			<link>http://www.decell.org/default.asp?id=134</link>
			<title><![CDATA[【转】 c语言string类函数实现汇总]]></title>
			<author>decell@163.com(admin)</author>
			<category><![CDATA[嵌入式技术]]></category>
			<pubDate>Fri,27 Aug 2010 11:06:31 +0800</pubDate>
			<guid>http://www.decell.org/default.asp?id=134</guid>	
		<description><![CDATA[【转】&nbsp;c语言string类函数实现汇总<br/><a href="http://blog.csdn.net/roger0710/archive/2010/04/15/5489170.aspx" target="_blank">http://blog.csdn.net/roger0710/archive/2010/04/15/5489170.aspx</a><br/><br/>看到很多地方都面试或者考试都要涉及字符串的很多知识&nbsp;有的需要自己写字符串&nbsp;最近看书的收集了一些&nbsp;算是摘抄&nbsp;然后在其中加了点我自己的感受&nbsp;嘿嘿<br/><br/>strcpy&nbsp;函数&nbsp;，作用是将一个字符串的字符复制到另一个字符串中<br/><br/>char&nbsp;*&nbsp;strcpy(char&nbsp;*destination&nbsp;,const&nbsp;char&nbsp;*&nbsp;source)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;while(*destination++=*source++);//看这一句话写的，精炼间断而又让人一目了然<br/><br/>&nbsp;&nbsp;&nbsp;//我用while写肯定是要三条语句，循环变量，赋值，递增，唉。。。这就是菜鸟啊<br/><br/>&nbsp;&nbsp;&nbsp;return(destination-1);<br/><br/>}<br/><br/>strcat函数，作用是将一个串的内容追加到另一个串上<br/><br/>char&nbsp;*strcat(char&nbsp;*target,const&nbsp;char&nbsp;*&nbsp;source)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;char&nbsp;*original=target;<br/><br/>&nbsp;&nbsp;&nbsp;while(*target)//这里可以看出指针和数组下标的不同，一直都觉得指针式很有优势的<br/><br/>&nbsp;&nbsp;&nbsp;target++;<br/><br/>&nbsp;&nbsp;&nbsp;while(*target++=*source++);<br/><br/>&nbsp;&nbsp;&nbsp;return(original);//注意到与上面一个函数返回的不同<br/><br/>}<br/><br/>strncat函数，这个不常用，作用是给字符串追加了N个字符<br/><br/>char&nbsp;*strcat(char&nbsp;*destination&nbsp;,const&nbsp;char&nbsp;*&nbsp;source，int&nbsp;n)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;char&nbsp;*original=destination;<br/><br/>&nbsp;&nbsp;&nbsp;int&nbsp;i=0;<br/><br/>&nbsp;&nbsp;&nbsp;while(*destination&nbsp;)<br/><br/>&nbsp;&nbsp;&nbsp;destination&nbsp;++;<br/><br/>&nbsp;&nbsp;&nbsp;while((i++&lt;n)&amp;&amp;(*destination&nbsp;++=*source++));//我忍不住再一次赞叹一下这个循环语句<br/><br/>&nbsp;&nbsp;&nbsp;//这个容错性的想到也很牛，只要n为负数，就将目标字符串改为空<br/><br/>&nbsp;&nbsp;&nbsp;if(i&gt;n)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*destination=NULL;<br/><br/>&nbsp;&nbsp;&nbsp;return(original);<br/><br/>}<br/><br/>strlwr&nbsp;和&nbsp;strupr函数&nbsp;这两个函数实现起来比较简单，就不列了&nbsp;：）<br/><br/>str_index函数&nbsp;作用是返回索引到串的首次出现<br/><br/>int&nbsp;str_index(const&nbsp;char*string,&nbsp;char&nbsp;letter)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;char&nbsp;*original=string;<br/><br/>&nbsp;&nbsp;&nbsp;while((*string!=letter)&amp;&amp;(*string))<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string++;<br/><br/>&nbsp;&nbsp;&nbsp;return(string-original);//这个返回方法，没有一定功力估计很难想出来，至少脑子里不会首先会想到这样写<br/><br/>}<br/><br/>strrchr函数&nbsp;也是不常用的函数&nbsp;作用是搜索字符在字符串中的末次出现<br/><br/>char&nbsp;*strrchr(const&nbsp;char&nbsp;*string,&nbsp;char&nbsp;letter)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;*ptr=NULL;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(*string)//这个逻辑在很多地方都有用<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(*string==letter)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ptr=string;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string++;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(ptr);<br/><br/>}<br/><br/>strchr函数&nbsp;作用是获取字符串中第一次出现某个字符<br/><br/>char&nbsp;*strchr(const&nbsp;char&nbsp;*string,&nbsp;char&nbsp;letter)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while((*string!=letter)&amp;&amp;(*string))<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string++;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(string);<br/><br/>}<br/><br/>strr_index函数&nbsp;作用是返回指向字符串末次出现的索引<br/><br/>int&nbsp;strr_index(const&nbsp;char&nbsp;*string,char&nbsp;letter)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;*original=string;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;*ptr=NULL;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(*string)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(*string==letter)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ptr=string;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string++<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;return((*ptr)?ptr-original:string-original);//要么返回末次出现的索引，要么返回字符串的长度<br/><br/>}<br/><br/>charcnt函数&nbsp;作用是计算字符串中字符出现的次数<br/><br/>int&nbsp;charcnt(const&nbsp;char&nbsp;*string,char&nbsp;letter)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;count=0;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;while(*string)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(*string==letter)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count++;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(count);<br/><br/>}<br/><br/>strrev函数&nbsp;作用是将字符串内容反转<br/><br/>char&nbsp;*strrev(char&nbsp;*string)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;*original=string;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;*forward=string;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;tmp;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(*string)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string++;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(forward&lt;string)//逻辑和交换两个数差不多<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp=*(--string);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*string=*forward;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*forward++=tmp;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(original);<br/><br/>}<br/><br/>strset函数&nbsp;作用是将某特定字符赋给字符串&nbsp;相当于用某一个字符重置字符串&nbsp;不是很难的函数&nbsp;：）<br/><br/>strcmp函数&nbsp;作用是比较两个字符串&nbsp;相同返回0，第一个大返回-1&nbsp;，第二个大返回1<br/><br/>int&nbsp;strcmp(const&nbsp;char&nbsp;*s1,&nbsp;const&nbsp;char&nbsp;*s2)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;while((*s1==*s2)&amp;&amp;(*s1))//这个比较的方式很简练吧，也很有逻辑<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s1++;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s2++;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;if((*s1==*s2)&amp;&amp;(!*s1))<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(0);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if((*s1)&amp;&amp;(!*s2))<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(-1);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if((!*s1)&amp;&amp;(*s2))<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(1);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;else<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return((*s1&gt;*s2)?-1:1);<br/><br/>}<br/><br/>strncmp函数&nbsp;作用是比较两个字符串的前N个字符&nbsp;实现和上面的函数很类似&nbsp;只是要添加一个控制变量控制下长度&nbsp;:&nbsp;)<br/><br/>strdup函数&nbsp;&nbsp;作用是复制字符串的内容<br/><br/>strdup(const&nbsp;char&nbsp;*s1)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;*ptr;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;if((ptr=malloc(strlen(s1)+1)))<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(ptr,s1);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;return(ptr);<br/><br/>}<br/><br/>strspn函数&nbsp;作用是从给定字符序列中查找字符的首次出现<br/><br/>size_t&nbsp;strspn（const&nbsp;char&nbsp;*s1,&nbsp;const&nbsp;char&nbsp;*s2)//这个函数我看了很久才明白是什么意思，比如第一个参数传abcDef,第二个传cbA,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//按照顺序查找第一个字符串，可以找到第一个没有在第二个字符串中出现的字符是&#39;D&#39;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//返回这个字符在第一个字符串中的索引，也就是3,另外，为什么不用int而用size_t做<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//返回值，是因为site_t是unsigned&nbsp;int，也就是正数<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;i,j;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;*s1;i++,s1++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(j=0;&nbsp;s2[j];&nbsp;j++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(*s1==s2[j])<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(s2[j]==NULL)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(i);<br/><br/>}<br/><br/>strstr函数&nbsp;作用是在字符串中查找子字符串&nbsp;虽然返回值是char*&nbsp;但是这个函数应该在判断有没有找到子字符串情况下用的多些<br/><br/>char&nbsp;*&nbsp;strstr(const&nbsp;char&nbsp;*s1,const&nbsp;char&nbsp;*s2)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;i,j,k;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;&nbsp;s1[i];&nbsp;i++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(j=i,k=0;&nbsp;s1[j]==s2[k];&nbsp;j++,k++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!s2[k+1])<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(s1+i)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(NULL);<br/><br/>}<br/><br/>strstr_cnt函数&nbsp;作用是计算字符串出现的次数&nbsp;实现差不多是strstr&nbsp;和cnt的组合&nbsp;:&nbsp;)<br/><br/>substring_index函数&nbsp;作用是给子字符串获取索引&nbsp;只要将strstr的返回值改成i就可以了&nbsp;:&nbsp;)<br/><br/>r_strstr函数&nbsp;作用是获取子字符串最右端出现&nbsp;和strstr差不多&nbsp;然后参照一般的查找最右端的函数&nbsp;:&nbsp;)<br/><br/>strstr_rem函数&nbsp;作用是从字符串中删除子字符串<br/><br/>char&nbsp;*&nbsp;strstr_rem(char&nbsp;*string,&nbsp;char&nbsp;*substring)//我没有仔细看这个函数，我有点懒，嘿嘿，但是按照上面的strstr在找到字符串后进行<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//进行替换，具体过程没看&nbsp;列出来&nbsp;可以学习<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;i,j,k,loc=-1;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;&nbsp;string[i]&amp;&amp;(loc==-1);&nbsp;i++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(j=i,k=0;&nbsp;string[j]==substring[k];&nbsp;j++,k++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!substring[k+1])<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loc=i;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(loc!=-1)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(k=0;&nbsp;substr[k];k++);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(j=loc;i=loc+k,string[i];&nbsp;j++,&nbsp;i++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string[j]=string[i];<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string[i]=NULL;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(string)<br/><br/>}<br/><br/>strstr_rep函数&nbsp;作用是用另一个字符串代替子字符串<br/><br/>char&nbsp;*strstr_rep(char&nbsp;*source,&nbsp;char&nbsp;*old&nbsp;,&nbsp;char&nbsp;*new)<br/><br/>{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;*original=source;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;temp[256];<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;old_length=strlen(old);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;i,j,k,location=-1;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;&nbsp;source[i]&amp;&amp;(location==-1);&nbsp;i++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(j=i,k=0;&nbsp;source[j]==old&nbsp;[k];&nbsp;j++,k++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!old&nbsp;[k+1])<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location=i;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(location!=-1)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(j=0;j&lt;location;j++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp[j]=source[j];<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;new[i];i++,j++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp[j]=new[i];<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(k=location+old_length;source[k];k++,j++)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp[j]=source[k];<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp[j]=NULL;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;&nbsp;source[i]=temp[i];i++);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(original);<br/><br/>}]]></description>
		</item>
		
			<item>
			<link>http://www.decell.org/default.asp?id=131</link>
			<title><![CDATA[Verilog HDL 综合要点[2] - 循环的综合 part1]]></title>
			<author>decell@163.com(admin)</author>
			<category><![CDATA[嵌入式技术]]></category>
			<pubDate>Thu,24 Jun 2010 17:33:49 +0800</pubDate>
			<guid>http://www.decell.org/default.asp?id=131</guid>	
		<description><![CDATA[1.周期性行为中的循环如果迭代次数在仿真前能由编译器确定(即迭代次数是固定的并且与数据无关)，这种循环被称为是静态的或是独立的。如果循环次数石油运算中的某个变量决定的，则这种循环称做是与数据相关的。<br/><br/>2.原则上说，静态循环能够用repeat，for，while和forever来综合，但是一个特定的厂商可能会选择将静态循环的描述风格限定为对某个特定结构的描述。最实用的循环形式是for循环，那些没有内部定时控制的非静态循环会引发问题，它们不能综合。<br/><br/>3.对于不带内嵌定时控制的静态循环，那么他的计算动作是一个隐式的组合。这种循环可以通过展开，不用存储器且在瞬间完成。<br/><br/>4.如果一个静态循环有内嵌的边沿敏感事件表达式，该循环的计算行为可以被同步并且分布到一个或多个时钟周期上。该行为就是循环的每次迭代都在时钟沿之后进行的模糊状态机。]]></description>
		</item>
		
			<item>
			<link>http://www.decell.org/default.asp?id=130</link>
			<title><![CDATA[Verilog HDL 综合要点[1] - mux结构及条件补全]]></title>
			<author>decell@163.com(admin)</author>
			<category><![CDATA[嵌入式技术]]></category>
			<pubDate>Sat,19 Jun 2010 13:55:14 +0800</pubDate>
			<guid>http://www.decell.org/default.asp?id=130</guid>	
		<description><![CDATA[1.&nbsp;如果case语句或者if&nbsp;-&nbsp;else&nbsp;-&nbsp;if语句中的条件语句不是互为唯一的，那么该语句将被综合为优先级结构；如果条件语句唯一，则被综合为mux结构。<br/>//综合为优先级结构<br/>always&nbsp;@(data)&nbsp;begin<br/>&#160;&#160;&#160;&#160;casex(data)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b1xxx_xxxx&nbsp;:&nbsp;code&nbsp;=&nbsp;7;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b01xx_xxxx&nbsp;:&nbsp;code&nbsp;=&nbsp;6;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b001x_xxxx&nbsp;:&nbsp;code&nbsp;=&nbsp;5;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0001_xxxx&nbsp;:&nbsp;code&nbsp;=&nbsp;4;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0000_1xxx&nbsp;:&nbsp;code&nbsp;=&nbsp;3;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0000_01xx&nbsp;:&nbsp;code&nbsp;=&nbsp;2;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0000_001x&nbsp;:&nbsp;code&nbsp;=&nbsp;1;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0000_0001&nbsp;:&nbsp;code&nbsp;=&nbsp;0;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;default&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&nbsp;:&nbsp;code&nbsp;=&nbsp;3&#39;bx;<br/>&#160;&#160;&#160;&#160;endcase<br/>end<br/>//综合为mux结构<br/>always&nbsp;@(data)&nbsp;begin<br/>&#160;&#160;&#160;&#160;case(data)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0000_0001:&nbsp;code&nbsp;=&nbsp;0;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0000_0010:&nbsp;code&nbsp;=&nbsp;1;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0000_0100:&nbsp;code&nbsp;=&nbsp;2;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0000_1000:&nbsp;code&nbsp;=&nbsp;3;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0001_0000:&nbsp;code&nbsp;=&nbsp;4;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0010_0000:&nbsp;code&nbsp;=&nbsp;5;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b0100_0000:&nbsp;code&nbsp;=&nbsp;6;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;8&#39;b1000_0000:&nbsp;code&nbsp;=&nbsp;7;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;default:&nbsp;code&nbsp;=&nbsp;3&#39;bx;<br/>&#160;&#160;&#160;&#160;endcase<br/>end<br/><br/>2.&nbsp;如果case或if&nbsp;-&nbsp;else&nbsp;-&nbsp;if&nbsp;语句中语句是完整的，也就是各种条件可能都出现了，则不需要综合出锁存器。如果确实有条件是无关紧要的，或是根本不可能出现的，通过使用带任意值的default语句或else语句补全，可以缩减实现的器件尺寸<br/>//完全不会产生锁存的设计<br/>always&nbsp;@(data_3&nbsp;o&#114;&nbsp;data_2&nbsp;o&#114;&nbsp;data_1&nbsp;o&#114;&nbsp;data_0&nbsp;o&#114;&nbsp;sel&#101;ct)&nbsp;begin<br/>&#160;&#160;&#160;&#160;<br/>&#160;&#160;&#160;&#160;case&nbsp;(sel&#101;ct)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;0:&nbsp;mux_in&nbsp;=&nbsp;data_3;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1:&nbsp;mux_in&nbsp;=&nbsp;data_2;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2:&nbsp;mux_in&nbsp;=&nbsp;data_1;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3:&nbsp;mux_in&nbsp;=&nbsp;data_0;&nbsp;&nbsp;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;default:&nbsp;mux_in&nbsp;=&nbsp;32&#39;bx;<br/>&#160;&#160;&#160;&#160;endcase<br/>end<br/>//这样也不会产生锁存，因为default语句补全了case语句<br/>always&nbsp;@(data_3&nbsp;o&#114;&nbsp;data_2&nbsp;o&#114;&nbsp;data_1&nbsp;o&#114;&nbsp;data_0&nbsp;o&#114;&nbsp;sel&#101;ct)&nbsp;begin<br/>&#160;&#160;&#160;&#160;<br/>&#160;&#160;&#160;&#160;case&nbsp;(sel&#101;ct)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;0:&nbsp;mux_in&nbsp;=&nbsp;data_3;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1:&nbsp;mux_in&nbsp;=&nbsp;data_2;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2:&nbsp;mux_in&nbsp;=&nbsp;data_1;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//3:&nbsp;mux_in&nbsp;=&nbsp;data_0;&nbsp;&nbsp;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;default:&nbsp;mux_in&nbsp;=&nbsp;32&#39;bx;<br/>&#160;&#160;&#160;&#160;endcase<br/>end<br/>//这样需要锁存<br/>always&nbsp;@(data_3&nbsp;o&#114;&nbsp;data_2&nbsp;o&#114;&nbsp;data_1&nbsp;o&#114;&nbsp;data_0&nbsp;o&#114;&nbsp;sel&#101;ct)&nbsp;begin<br/>&#160;&#160;&#160;&#160;<br/>&#160;&#160;&#160;&#160;case&nbsp;(sel&#101;ct)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;0:&nbsp;mux_in&nbsp;=&nbsp;data_3;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1:&nbsp;mux_in&nbsp;=&nbsp;data_2;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2:&nbsp;mux_in&nbsp;=&nbsp;data_1;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//3:&nbsp;mux_in&nbsp;=&nbsp;data_0;&nbsp;&nbsp;<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//default:&nbsp;mux_in&nbsp;=&nbsp;32&#39;bx;<br/>&#160;&#160;&#160;&#160;endcase<br/>end]]></description>
		</item>
		
			<item>
			<link>http://www.decell.org/default.asp?id=126</link>
			<title><![CDATA[【转】CPU地址空间]]></title>
			<author>decell@163.com(admin)</author>
			<category><![CDATA[嵌入式技术]]></category>
			<pubDate>Sun,30 May 2010 22:35:58 +0800</pubDate>
			<guid>http://www.decell.org/default.asp?id=126</guid>	
		<description><![CDATA[转自：<a href="http://joe.is-programmer.com/posts/17559.html" target="_blank">http://joe.is-programmer.com/posts/17559.html</a><br/>CPU地址空间<br/>（一）地址的概念<br/><br/>1）物理地址：CPU地址总线传来的地址，由硬件电路控制其具体含义。物理地址中很大一部分是留给内存条中的内存的，但也常被映射到其他存储器上&nbsp;（如显存、BIOS等）。在程序指令中的虚拟地址经过段映射和页面映射后，就生成了物理地址，这个物理地址被放到CPU的地址线上。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;物理地址空间，一部分给物理RAM（内存）用，一部分给总线用，这是由硬件设计来决定的，因此在32&nbsp;bits地址线的x86处理器中，物理地址空间是2的32次方，即4GB，但物理RAM一般不能上到4GB，因为还有一部分要给总线用（总线上还挂着别的&nbsp;许多设备）。在PC机中，一般是把低端物理地址给RAM用，高端物理地址给总线用。<br/>&nbsp;<br/>2）总线地址：总线的地址线或在地址周期上产生的信号。外设使用的是总线地址，CPU使用的是物理地址。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;物理地址与总线地址之间的关系由系统的设计决定的。在x86平台上，物理地址就是总线地址，这是因为它们共享相同的地址空间——这句话有点难理解，详见下&nbsp;面的“独立编址”。在其他平台上，可能需要转换/映射。比如：CPU需要访问物理地址是0xfa000的单元，那么在x86平台上，会产生一个PCI总线&nbsp;上对0xfa000地址的访问。因为物理地址和总线地址相同，所以凭眼睛看是不能确定这个地址是用在哪儿的，它或者在内存中，或者是某个卡上的存储单元，&nbsp;甚至可能这个地址上没有对应的存储器。<br/><br/>3）虚拟地址：现代操作系统普遍采用虚拟内存管理（Virtual&nbsp;Memory&nbsp;Management）机制，这需要MMU（Memory&nbsp;Management&nbsp;Unit）的支持。MMU通常是CPU的一部分，如果处理器没有MMU，或者有MMU但没有启用，CPU执行单元发出的内存地址将直接传到芯片引脚上，被&nbsp;内存芯片（物理内存）接收，这称为物理地址（Physical&nbsp;Address），如果处理器启用了MMU，CPU执行单元发出的内存地址将被MMU截获，从CPU到MMU的地址称为虚拟地址（Virtual&nbsp;Address），而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上，也就是将虚拟地址映射成物理地址。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Linux中，进程的4GB（虚拟）内存分为用户空间、内核空间。用户空间分布为0~3GB（即PAGE_OFFSET，在0X86中它等于&nbsp;0xC0000000）<br/>，剩下的1G为内核空间。程序员只能使用虚拟地址。系统中每个进程有各自的私有用户空间（0～3G），这个空间对系统中的其他进程是不可见的。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPU发出取指令请求时的地址是当前上下文的虚拟地址，MMU再从页表中找到这个虚拟地址的物理地址，完成取指。同样读取数据的也是虚拟地址，比如mov&nbsp;ax,&nbsp;var.&nbsp;编译时var就是一个虚拟地址，也是通过MMU从也表中来找到物理地址，再产生总线时序，完成取数据的。<br/><br/><br/>（二）编址方式<br/>1）外设都是通过读写设备上的寄存器来进行的，外设寄存器也称为“I/O端口”，而IO端口有两种编址方式：独立编址和统一编制。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;统一编址：外设接口中的IO寄存器（即IO端口）与主存单元一样看待，每个端口占用一个存储单元的地址，将主存的一部分划出来用作IO地址空间，如，在&nbsp;PDP-11中，把最高的4K主存作为IO设备寄存器地址。端口占用了存储器的地址空间，使存储量容量减小。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;统一编址也称为“I/O内存”方式，外设寄存器位于“内存空间”（很多外设有自己的内存、缓冲区，外设的寄存器和内存统称“I/O空间”）。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如，Samsung的S3C2440，是32位ARM处理器，它的4GB地址空间被外设、RAM等瓜分：<br/>0x8000&nbsp;1000&nbsp;&nbsp;&nbsp;&nbsp;LED&nbsp;8*8点阵的地址<br/>0x4800&nbsp;0000&nbsp;~&nbsp;0x6000&nbsp;0000&nbsp;&nbsp;SFR（特殊暂存器）地址空间<br/>0x3800&nbsp;1002&nbsp;&nbsp;&nbsp;键盘地址<br/>0x3000&nbsp;0000&nbsp;~&nbsp;0x3400&nbsp;0000&nbsp;&nbsp;SDRAM空间&nbsp;<br/>0x2000&nbsp;0020&nbsp;~&nbsp;0x2000&nbsp;002e&nbsp;&nbsp;IDE<br/>0x1900&nbsp;0300&nbsp;&nbsp;&nbsp;CS8900<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;独立编址（单独编址）：IO地址与存储地址分开独立编址，I/0端口地址不占用存储空间的地址范围，这样，在系统中就存在了另一种与存储地址无关的IO地&nbsp;址，CPU也必须具有专用与输入输出操作的IO指令（IN、OUT等）和控制逻辑。独立编址下，地址总线上过来一个地址，设备不知道是给IO端口的、还是&nbsp;给存储器的，于是处理器通过MEMR/MEMW和IOR/IOW两组控制信号来实现对I/O端口和存储器的不同寻址。如，intel&nbsp;80x86就采用单独编址，CPU内存和I/O是一起编址的，就是说内存一部分的地址和I/O地址是重叠的。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;独立编址也称为“I/O端口”方式，外设寄存器位于“I/O（地址）空间”。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于x86架构来说，通过IN/OUT指令访问。PC架构一共有65536个8bit的I/O端口，组成64K个I/O地址空间，编号从&nbsp;0~0xFFFF，有16位，80x86用低16位地址线A0-A15来寻址。连续两个8bit的端口可以组成一个16bit的端口，连续4个组成一个&nbsp;32bit的端口。I/O地址空间和CPU的物理地址空间是两个不同的概念，例如I/O地址空间为64K，一个32bit的CPU物理地址空间是4G。&nbsp;如，在Intel&nbsp;8086+Redhat9.0&nbsp;下用“more&nbsp;/proc/ioports”可看到：<br/>0000-001f&nbsp;:&nbsp;dma1<br/>0020-003f&nbsp;:&nbsp;pic1<br/>0040-005f&nbsp;:&nbsp;timer<br/>0060-006f&nbsp;:&nbsp;keyboard<br/>0070-007f&nbsp;:&nbsp;rtc<br/>0080-008f&nbsp;:&nbsp;dma&nbsp;page&nbsp;reg<br/>00a0-00bf&nbsp;:&nbsp;pic2<br/>00c0-00df&nbsp;:&nbsp;dma2<br/>00f0-00ff&nbsp;:&nbsp;fpu<br/>0170-0177&nbsp;:&nbsp;ide1<br/>……<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不过Intel&nbsp;x86平台普通使用了名为内存映射（MMIO）的技术，该技术是PCI规范的一部分，IO设备端口被映射到内存空间，映射后，CPU访问IO端口就如同访&nbsp;问内存一样。看Intel&nbsp;TA&nbsp;719文档给出的x86/x64系统典型内存地址分配表：<br/>系统资源&nbsp;&nbsp;占用<br/>------------------------------------------------------------------------<br/>BIOS&nbsp;&nbsp;1M<br/>本地APIC&nbsp;&nbsp;4K<br/>芯片组保留&nbsp;2M<br/>IO&nbsp;APIC&nbsp;&nbsp;4K<br/>PCI设备&nbsp;&nbsp;256M<br/>PCI&nbsp;Express设备&nbsp;256M<br/>PCI设备（可选）&nbsp;256M<br/>显示帧缓存&nbsp;16M<br/>TSEG&nbsp;&nbsp;1M<br/><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于某一既定的系统，它要么是独立编址、要么是统一编址，具体采用哪一种则取决于CPU的体系结构。&nbsp;如，PowerPC、m68k等采用统一编址，而X86等则采用独立编址，存在IO空间的概念。目前，大多数嵌入式微控制器如ARM、PowerPC等并&nbsp;不提供I/O空间，仅有内存空间，可直接用地址、指针访问。但对于Linux内核而言，它可能用于不同的CPU，所以它必须都要考虑这两种方式，于是它采&nbsp;用一种新的方法，将基于I/O映射方式的或内存映射方式的I/O端口通称为“I/O区域”（I/O&nbsp;region），不论你采用哪种方式，都要先申请IO区域：request_resource()，结束时释放&nbsp;它：release_resource()。<br/>&nbsp;<br/><br/>2）对外设的访问<br/><br/>1、访问I/O内存的流程是：request_mem_region()&nbsp;-&gt;&nbsp;ioremap()&nbsp;-&gt;&nbsp;ioread8()/iowrite8()&nbsp;-&gt;&nbsp;iounmap()&nbsp;-&gt;&nbsp;release_mem_region()&nbsp;。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;前面说过，IO内存是统一编址下的概念，对于统一编址，IO地址空间是物理主存的一部分，对于编程而言，我们只能操作虚拟内存，所以，访问的第一步就是要把设备所处的物理地址映射到虚拟地址，Linux2.6下用ioremap():<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;*ioremap(unsigned&nbsp;long&nbsp;offset,&nbsp;unsigned&nbsp;long&nbsp;size);<br/>然后，我们可以直接通过指针来访问这些地址，但是也可以用Linux内核的一组函数来读写：<br/>ioread8(),&nbsp;iowrite16(),&nbsp;ioread8_rep(),&nbsp;iowrite8_rep()......<br/><br/>2、访问I/O端口<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;访问IO端口有2种途径：I/O映射方式（I/O－mapped）、内存映射方式（Memory－mapped）。前一种途径不映射到内存空间，直接使用&nbsp;intb()/outb()之类的函数来读写IO端口；后一种MMIO是先把IO端口映射到IO内存（“内存空间”），再使用访问IO内存的函数来访问&nbsp;IO端口。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;ioport_map(unsigned&nbsp;long&nbsp;port,&nbsp;unsigned&nbsp;int&nbsp;count);<br/>通过这个函数，可以把port开始的count个连续的IO端口映射为一段“内存空间”，然后就可以在其返回的地址是像访问IO内存一样访问这些IO端口。<br/>]]></description>
		</item>
		
			<item>
			<link>http://www.decell.org/default.asp?id=124</link>
			<title><![CDATA[mail list]]></title>
			<author>decell@163.com(admin)</author>
			<category><![CDATA[嵌入式技术]]></category>
			<pubDate>Thu,15 Apr 2010 02:23:09 +0800</pubDate>
			<guid>http://www.decell.org/default.asp?id=124</guid>	
		<description><![CDATA[做了这么久的Linux开发，读了这么多mail&nbsp;list，今天才第一次在mail&nbsp;list说话。说来惭愧，不过看到自己的post出现在list中，那种归属感无可比拟。纪念一下。<br/><br/>------------------------------<br/><br/>Message:&nbsp;5<br/>Date:&nbsp;Wed,&nbsp;14&nbsp;Apr&nbsp;2010&nbsp;14:34:04&nbsp;+0800<br/>From:&nbsp;Terren&nbsp;Chow&nbsp;&lt;terren.chow@gmail.com&gt;<br/>To:&nbsp;linuxppc-dev@lists.ozlabs.org<br/>Subject:&nbsp;Questions&nbsp;about&nbsp;creating&nbsp;a&nbsp;OF&nbsp;platform&nbsp;device<br/>Message-ID:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;q2t9faa26521004132334ta3e05513u2b9b569c47fbe212@mail.gmail.com&gt;<br/>Content-Type:&nbsp;text/plain;&nbsp;charset=&#34;iso-8859-1&#34;<br/><br/>Dear&nbsp;all,<br/>&nbsp;&nbsp;&nbsp;I&#39;m&nbsp;new&nbsp;to&nbsp;PPC&nbsp;Linux&nbsp;development.&nbsp;Recently&nbsp;I&#39;m&nbsp;learning&nbsp;how&nbsp;to&nbsp;write&nbsp;a<br/>Linux&nbsp;device&nbsp;driver&nbsp;on&nbsp;MPC5121&nbsp;based&nbsp;embedded&nbsp;system.&nbsp;I&#39;m&nbsp;just&nbsp;confused<br/>about&nbsp;the&nbsp;OF&nbsp;related&nbsp;code&nbsp;in&nbsp;the&nbsp;kernel.<br/>&nbsp;&nbsp;&nbsp;I&nbsp;know&nbsp;in&nbsp;the&nbsp;Linux&nbsp;device&nbsp;driver&nbsp;model,&nbsp;a&nbsp;driver&nbsp;is&nbsp;attached&nbsp;to&nbsp;a<br/>device&nbsp;through&nbsp;the&nbsp;bus_type&nbsp;methods.&nbsp;For&nbsp;example,&nbsp;the&nbsp;&nbsp;platform_driver&nbsp;is<br/>attached&nbsp;to&nbsp;a&nbsp;platform&nbsp;device&nbsp;through&nbsp;the&nbsp;register_platform_driver()&nbsp;method.<br/>This&nbsp;method&nbsp;will&nbsp;scan&nbsp;over&nbsp;the&nbsp;device&nbsp;list&nbsp;in&nbsp;the&nbsp;bus,&nbsp;and&nbsp;perform&nbsp;probe()<br/>method&nbsp;when&nbsp;the&nbsp;match()&nbsp;method&nbsp;return&nbsp;ok.<br/>&nbsp;&nbsp;My&nbsp;question&nbsp;is,&nbsp;in&nbsp;PPC&nbsp;Linux,&nbsp;there&nbsp;is&nbsp;a&nbsp;structure&nbsp;named&nbsp;*<br/>of_platform_driver*&nbsp;which&nbsp;is&nbsp;similar&nbsp;to&nbsp;*platform_driver*&nbsp;and&nbsp;there&nbsp;is&nbsp;also<br/>a&nbsp;bus_type&nbsp;named&nbsp;*of_platform_bus_type*&nbsp;which&nbsp;is&nbsp;similar&nbsp;to&nbsp;*<br/>platform_bus_type*.&nbsp;But&nbsp;I&nbsp;can&#39;t&nbsp;find&nbsp;any&nbsp;information&nbsp;about&nbsp;the&nbsp;structure<br/>of_platform_device.&nbsp;How&nbsp;do&nbsp;the&nbsp;kernel&nbsp;cr&#101;ate&nbsp;the&nbsp;of_platform_device&nbsp;and<br/>place&nbsp;them&nbsp;into&nbsp;the&nbsp;device&nbsp;list&nbsp;in&nbsp;the&nbsp;*platform_bus_type*&nbsp;?&nbsp;I&nbsp;search&nbsp;the<br/>Internet&nbsp;and&nbsp;I&nbsp;can&#39;t&nbsp;find&nbsp;any&nbsp;information&nbsp;about&nbsp;this.Could&nbsp;anyone&nbsp;give&nbsp;me<br/>some&nbsp;information&nbsp;so&nbsp;that&nbsp;I&nbsp;can&nbsp;find&nbsp;out&nbsp;the&nbsp;magic&nbsp;behind.&nbsp;Thanks!<br/><br/>--<br/>Terren.Chow<br/>College&nbsp;of&nbsp;Informatics,&nbsp;SCAU<br/>Graduate&nbsp;Student<br/>Lab&nbsp;of&nbsp;Embedded&nbsp;System&nbsp;and&nbsp;Wireless&nbsp;Sensor&nbsp;Network<br/>MSN:&nbsp;terren.chow@hotmail.com]]></description>
		</item>
		
			<item>
			<link>http://www.decell.org/default.asp?id=123</link>
			<title><![CDATA[关于串口的CTS与RTS]]></title>
			<author>decell@163.com(admin)</author>
			<category><![CDATA[嵌入式技术]]></category>
			<pubDate>Wed,18 Nov 2009 19:47:35 +0800</pubDate>
			<guid>http://www.decell.org/default.asp?id=123</guid>	
		<description><![CDATA[本文转自<a href="http://www.edacn.net/html/89/118589-49762.html" target="_blank">http://www.edacn.net/html/89/118589-49762.html</a><br/><br/>网上看到一篇很好的说明CTS与RTS作用的讨论，转过来保存。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;很久很久以前，计算机还没有出现，那时就已经存在了(计算机)史前的串口设备(电传打字机，工控测量设备，通信调制解调器)，为了连接这些串口，EIA制定了RS232标准，采用DB25接插件，支持同步和异步串口，D型的接口可以有效防止插反。标准化给使用带来了便利。<br/>&nbsp;&nbsp;&nbsp;&nbsp;时光荏苒，个人计算机出现了，这些已有的串口设备毫无疑问地成为了最初的外设，自然而然地RS232标准被个人计算机采纳。但是设备制造商倾向于体积更小，成本更低的接口，因此，将DB25中未使用的和支持同步模式的引脚去掉，形成DB9。最初的情况相当混乱，因为DB9只定义了信号，却没有指定信号和引脚的对应关系，各个制造商只能自行定义。幸运的是，IBM的PC成了工业标准，DB9逐渐统一到IBM的定义上来。<br/>&nbsp;&nbsp;&nbsp;&nbsp;DB9只有9根线，遵循RS232标准。定义如下：<br/>&nbsp;&nbsp;&nbsp;&nbsp;DTR,DSR------DTE设备准备好/DCE设备准备好。主流控信号。<br/>&nbsp;&nbsp;&nbsp;&nbsp;RTS,CTS------&nbsp;请求发送/清除发送。用于半双工时，收发切换。属于辅助流控信号。半双工的意思是说，发的时候不收，收的时候不发。那么怎么区分收发呢？缺省时是DCE向&nbsp;DTE发送数据，当DTE决定向DCE发数据时，先有效RTS，表示DTE希望向DCE发送，一般DCE不能马上转换收发状态，DTE就通过监测CTS是否有效来判断可否发送，这样避免了DTE在DCE未准备好时发送所导致的数据丢失。<br/>&nbsp;&nbsp;&nbsp;&nbsp;全双工时，这两个信号一直有效即可。<br/>&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;随着计算机的日益普及，很多非RS232的串口也要接入PC机，如果为每一种新出现的串口都增加一个新的I/O口显然不现实，因为PC后面板位置有限，因此，将RS232串口和非RS232串口都通过RS232口接入是最佳方案。UART的U(通用)指的就是这个意思。早期ROM&nbsp;BIOS和DOS里的通信软件都是为RS232设计的，在没有检测到DCD有效前不会发送数据，因此，就连发送一个字符这样朴素的应用也要给出DCD、&nbsp;DTR、DSR等控制信号。因此，串口接头上要将一些控制线短接，或者干脆绕过系统软件自己写通信程序。<br/>&nbsp;&nbsp;&nbsp;&nbsp;到此，UART的涵义就总结为：通用的&nbsp;异步&nbsp;(串行)&nbsp;I/O口。<br/>&nbsp;&nbsp;&nbsp;&nbsp;就在UART冠以通用二字，准备一统江湖的时候，制造商们不满于它的速度、体积和灵活性(软件可配置)，推出了USB和1394串口。目前，笔记本上的&nbsp;UART串口有被取消的趋势，因而有网友发出了“没有串口，吾谁与归”的慨叹，古今多少事，都付笑谈中，USB取代UART是后话，暂且不表。<br/>&nbsp;&nbsp;&nbsp;&nbsp;话说自从贺氏(Hayes)公司推出了聪明猫(SmartModem)，他们制定的MODEM接口就成了业界标准，自此以后，所有公司制造的兼容猫都符合贺氏标准(连AT指令也兼容，大家一起抄他呗)。<br/>&nbsp;&nbsp;&nbsp;&nbsp;细观贺氏制定的MODEM串口，与RS232标准大不相同。DTR在整个通信过程中一直保持有效，DSR在MODEM上电后/可以拨号前有效(取决于软件对&nbsp;DSR的理解)，在通信过程的任意时刻，只要DTR/DSR无效，通信过程立即终止。在某种意义上，这也可以算是流控，但肯定不是RS232所指的那种主流控。如果拘泥于RS232，你是不会理解DTR和DSR的用途的。<br/>&nbsp;&nbsp;&nbsp;&nbsp;贺氏不但改了DTR和DSR，竟然连RTS和CTS的涵义也重新定义了。因此，RTS和CTS已经不具有最开始的意义了。从字面理解RTS和CTS，是用于半双工通信的，当DTE想从收模式改为发模式时，就有效RTS请求发送，DCE收到RTS请求后不能立即完成转换，需要一段时间，然后有效CTS通知DTE：DCE已经转到发模式，DTE可以开始发送了。在全双工时，RTS和CTS都缺省置为有效即可。然而，在贺氏的MODEM串口定义中，RTS和CTS用于硬件流控，和什么劳什子的全双工/半双工一点关系也没有。<br/>&nbsp;&nbsp;&nbsp;&nbsp;注意，硬件流控是靠软件实现的，之所以强调“硬件”二字，仅仅是因为硬件流控提供了用于流量情况指示的硬件连线，并不是说，你只要把线连上，硬件就能自己流控。如果软件不支持，光连上RTS和CTS是没有用的。<br/>&nbsp;&nbsp;&nbsp;&nbsp;RTS和CTS硬件流控的软件算法如下：(RTS有效表示PC机可以收，CTS有效表示MODEM可以收，这两个信号互相独立，分别指示一个方向的流量情况。)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;dengm&nbsp;发表于&nbsp;2005-1-14&nbsp;07:52&nbsp;侃单片机<br/>&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;PC端处理：<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;发.&nbsp;当&nbsp;发现（不一定及时发现）&nbsp;CTS&nbsp;(-3v&nbsp;to&nbsp;-15v)无效时，停止发送,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当&nbsp;发现（不一定及时发现）&nbsp;CTS&nbsp;(3v&nbsp;to&nbsp;15v)有效时，恢复发送；<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;收.&nbsp;0&lt;M&lt;N&lt;LEN_OF_RX_BUFFERS<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当接收buffers中的bytes&lt;M&nbsp;时，给&nbsp;RTS&nbsp;有效信号（+3v&nbsp;to&nbsp;+15v),<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当接收buffers中的bytes&gt;N&nbsp;时，给&nbsp;RTS&nbsp;无效信号（-3v&nbsp;to&nbsp;-15v);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;MODEM端处理：<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;同上，但RTS与CTS交换。<br/>&nbsp;&nbsp;&nbsp;&nbsp;<br/>]]></description>
		</item>
		
			<item>
			<link>http://www.decell.org/default.asp?id=121</link>
			<title><![CDATA[mpc5121手记--nand flash控制器]]></title>
			<author>decell@163.com(admin)</author>
			<category><![CDATA[嵌入式技术]]></category>
			<pubDate>Tue,17 Feb 2009 01:54:41 +0800</pubDate>
			<guid>http://www.decell.org/default.asp?id=121</guid>	
		<description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;mpc5121的nand&nbsp;flash控制器可以支持512、2k、4k&nbsp;page大小的nandflash。LPC，nand/PATA共用EMB接口，复用优先的仲裁由EMB仲裁器完成。获得总线仲裁时，他与PATA共享EMB_AD[0..31]，PATA占用EMB_AF[0..15]与EMB_AX[2..0]，nand占用EMB_AD[16..31]。<br/>&nbsp;&nbsp;&nbsp;mpc5121内部有一个4.5K大小的RAM，作为对nand&nbsp;flash进行操作的时候的数据输入/输出接口。该RAM完全模拟一块nand&nbsp;flash的page结构，共分为8个512&nbsp;Byte&nbsp;的main&nbsp;section和8个26&nbsp;byte的&nbsp;spare&nbsp;section。page大小为2K/4K的nand&nbsp;flash，也是根据这样分区的，2K&nbsp;page的nand&nbsp;flash的main区会被分成4个section，每section&nbsp;512B，同时spare区也会相应地分成4个section，每个section16B。<br/>&nbsp;&nbsp;&nbsp;打开ECC的情况下，写入操作的时候，现将目标数据写入该RAM。然后设定RBA设定目标section，最后设定FDI位，硬件会计算该section的ECC&nbsp;code，然后连同目标数据一起写入flash&nbsp;page。比如对于2K&nbsp;page的nand，如果RBA=0，则会把RAM中section0/1/2/3写入nand。虽然是一次完成，但是ECC是计算了四次的，每512B一次，也就是，先算section0的ECC，section0写入page&nbsp;main区的头512B，ECC则写入spare区的头16B，再算section1的ECC，section1写入page&nbsp;main区的第二个512B，ECC则写入spare区的第二个16B，如此类推。当然你也可以设RBA=4，这时将会把RAM中section4/5/6/7写入nand。RBA不能等于1/2/3/5/6/7。<br/>&nbsp;&nbsp;&nbsp;读与写类似，也是先设定RBA，设定FDO，数据会从nand&nbsp;flash读出，放到RBA指定的section中。也是先读第一个512B和第一个16B，再第二个512B和第二个16B。用户这时可以从RAM的spare&nbsp;section中读出写入时产生的ECC。写入是产生的ECC只能这样读，因为写入是产生的ECC是不会放入到spare&nbsp;section中的，他们直接被写入flash中。]]></description>
		</item>
		
			<item>
			<link>http://www.decell.org/default.asp?id=119</link>
			<title><![CDATA[[X-node] uC/OS-II v2.70]]></title>
			<author>decell@163.com(admin)</author>
			<category><![CDATA[嵌入式技术]]></category>
			<pubDate>Thu,05 Feb 2009 21:26:42 +0800</pubDate>
			<guid>http://www.decell.org/default.asp?id=119</guid>	
		<description><![CDATA[uC/OS-II&nbsp;v2.70&nbsp;成功在X-node上跑起来了。我没有使用uC/OS官方的IAR或GNU编译器，而是使用TI的CCE&nbsp;v3.2，所以又修改了一点源码，主要是汇编的格式和伪指令。有用CCE而又懒得去研究编译器语法的朋友可以向我要源码。版权归uC/OS-II的原作者所有。<br/><img src="http://ai.ee.ccu.edu.tw/os/projects/2006fall/team07/images/uc-OS-II-logo.gif" border="0" alt=""/>]]></description>
		</item>
		
			<item>
			<link>http://www.decell.org/default.asp?id=117</link>
			<title><![CDATA[X-node]]></title>
			<author>decell@163.com(admin)</author>
			<category><![CDATA[嵌入式技术]]></category>
			<pubDate>Mon,12 Jan 2009 15:00:25 +0800</pubDate>
			<guid>http://www.decell.org/default.asp?id=117</guid>	
		<description><![CDATA[最近做的一个WSN节点（其实很早就可以画的了，最近老板抓得紧了，于是重视了一下）。<br/>之所以叫X-node，是因为元器件是45度place的，板子看起来有点像X字形。<br/>MSP430+CC2500+CC2591。理论发射功率可以有20dbm。尺寸是45mm&nbsp;x&nbsp;30m。<br/><img src="http://i401.photobucket.com/albums/pp92/decell_chow/1169528528233994630.jpg" border="0" alt=""/><br/><br/>Happy&nbsp;birthday&nbsp;to&nbsp;Hannah！<br/>]]></description>
		</item>
		
			<item>
			<link>http://www.decell.org/default.asp?id=114</link>
			<title><![CDATA[ARM-ELF文件格式与GNU ARM Linker机制]]></title>
			<author>decell@163.com(admin)</author>
			<category><![CDATA[嵌入式技术]]></category>
			<pubDate>Mon,13 Oct 2008 23:38:18 +0800</pubDate>
			<guid>http://www.decell.org/default.asp?id=114</guid>	
		<description><![CDATA[【本站原创，转载请注明出处】<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这里所说的ARM系统基本文件格式，都是在基于ARM的嵌入式系统开发中常会碰到的文件格式。<br/>&nbsp;&nbsp;&nbsp;&nbsp;ARM系统基本文件格式有三种：<br/>1)&nbsp;BIN，平板式二进制格式，一般用于直接烧写到Flash中，也可以用于加载到monitor程序中。<br/>2)&nbsp;ELF，EXECUTABLE&nbsp;AND&nbsp;LINKABLE&nbsp;FORMAT，一种通用的OBJECT文件格式，一般由GNU&nbsp;COMPILER&nbsp;COLLECTION&nbsp;(GCC)产生。<br/>3)&nbsp;AXF，BIN格式的扩展版,主体部分同BIN，在文件头和尾加入了调试用的信息，用于AXD。<br/>&nbsp;&nbsp;&nbsp;&nbsp;本文主要讨论BIN与ELF。<br/>&nbsp;&nbsp;&nbsp;&nbsp;首先说明，ELF格式是一种OBJECT文件格式。一般OBJECT文件都可以分成三类：可重定位OBJECT文件，可执行OBJECT文件，共享OBJECT文件。ELF格式文件也可以分成这三种。<br/>&nbsp;&nbsp;&nbsp;&nbsp;首先说说可重定位OBJECT文件。这种OBJECT文件一般由GCC中的ASSEMBLER(as)产生(请不要认为GCC只是编译器)，里面除了二进制的机器代码，还有一些可用于进行重定位的信息。它主要是作为LINKER(ld)的输入，LINKER将跟据这些信息，将需要重定位的符号重定位，进而产生可执行的OBJECT文件。ELF格式的可重定位OBJECT文件由header与section组成。<br/>&nbsp;&nbsp;&nbsp;&nbsp;Header&nbsp;包括ELF&nbsp;header&nbsp;与&nbsp;section&nbsp;header.&nbsp;ELF&nbsp;header&nbsp;位于文件的头部，用于存储目标机器的架构，大小端配置，ELF&nbsp;header大小，object文件类型，section&nbsp;header&nbsp;在文件中的偏移，section&nbsp;header&#160;&#160;&#160;&#160;的大小，section&nbsp;header&nbsp;中的项目数等信息。Section&nbsp;header&nbsp;则定义了文件中每个section&nbsp;的类型，位置，大小等信息。Linker就是通过查找ELF&nbsp;header，找到section&nbsp;header&nbsp;的入口，再在section&nbsp;header&nbsp;中找到相应的section&nbsp;入口，进而定位到目标section&nbsp;的。<br/>&nbsp;&nbsp;&nbsp;&nbsp;Section&nbsp;包括&nbsp;<br/>.text&nbsp;&nbsp;&nbsp;&nbsp;：经过编译的机器代码。<br/>.rodata&nbsp;&nbsp;：只读的数据，例如printf(“hello!”)中的字符串hello。<br/>.data&nbsp;&nbsp;&nbsp;&nbsp;：已初始化的全局变量，局部变量将在运行时被存放在堆栈中，不会在.data或&nbsp;.bss段中出现。<br/>.bss&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;：未初始化的全局变量，在这里只是一个占位符，在object文件中并没有实际的存储空间。<br/>.symtab&nbsp;&nbsp;：符号表，用于存放程序中被定义的或被引用到的全局变量和函数的信息。<br/>.rel.text&nbsp;&nbsp;：一个保存着一系列在.text中的位置的列表。这些位置将在linker把这个文件与其它object文件合并时被修改，一般来说，这些位置都是保存着一些引用到全局变量或者外部函数的指令。引用局部变量或者本地函数的指令是不需要被修改的，因为局部变量和本地函数的地址一般都是使用PC相对偏移地址的。需要注意的是，这个section&nbsp;和下面的.rel.data在运行时并不需要，生成可执行的ELF&nbsp;object文件时会去掉这个section。<br/>.rel.data&nbsp;：保存全局变量的重定位信息。一般来说，如果一个全局变量它的初始化值是另一个全局变量的地址，或者是外部函数的地址，那么它就需要被重定位。<br/>.debug&nbsp;&nbsp;：保存debug信息。<br/>.strtab&nbsp;&nbsp;：&nbsp;一个字符串表，保存着.symtab和.debug&nbsp;,和各个section的名字。.symtab，.debug&nbsp;和section&nbsp;table里面，凡是保存name的域，其实都是保存了一个偏移值，通过这个偏移值在这个字符串表里面可以找到相应得字符串。<br/>&nbsp;&nbsp;&nbsp;&nbsp;下面仔细讨论一下.symtab：<br/>&nbsp;&nbsp;&nbsp;&nbsp;每一个可重定位的object文件，都会有一个.symtab。这个符号表保存了在这个object文件中所有被定义的和被引用的符号。当源程序是C&nbsp;语言程序时，.symtab&nbsp;中的符号直接来源于C编译器(cc1)。这里所说的符号主要有三种：<br/>1)&nbsp;在这个object文件中被定义的可以被其他object文件全局符号。在C语言源程序中，主要就是那些非静态（没有static&nbsp;修饰的）的全局变量和非静态的函数。在ARM汇编语言中，就是那些&nbsp;被EXPORT&nbsp;指令导出的变量。<br/>2)&nbsp;在这个object文件中引用到，但是在其他文件中定义的全局变量。在ARM汇编语言中就是通过IMPORT命令引入的变量<br/>3)&nbsp;本地变量。本地变量只在本object文件内可见。这里的本地变量指的是连接器本地变量，应该和一般的程序本地变量作区别。这里所指的本地变量，包括用static&nbsp;修饰的全局变量，object文件中section名称，源代码文件名称。一般意义上的本地变量，是在运行时由系统的运行时环境管理的，linker并不关心。<br/>&nbsp;&nbsp;&nbsp;&nbsp;每个符合上面条件的符号在.symtab文件中都会有一个数据项。这个数据项的数据结构是：<br/><br/>Typedef&nbsp;struct{<br/>&#160;&#160;&#160;&#160;int&nbsp;name;//符号名称，其实就是.strtab的偏移值<br/>&#160;&#160;&#160;&#160;int&nbsp;value;//在section中的位置，以相对section地址的偏移表示<br/>&#160;&#160;&#160;&#160;int&nbsp;size;//大小<br/>&#160;&#160;&#160;&#160;char&nbsp;type;//类型，一般是数据或函数<br/>&#160;&#160;&#160;&#160;char&nbsp;binding;//是本地变量还是全局变量<br/>&#160;&#160;&#160;&#160;char&nbsp;reserved;//保留的位<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;section;//符号所属的section。可选有：.text(用数字1代表)，.data(用数<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//3代表)，ABS（不应被重定位的符号），UND（在本object文件<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//中未定义的符号，可能在别的文件中定义），COM（一般的未初//始化的变量符号）。<br/>}ELF_sym<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;现在假设组成应用的各个模块都已经被汇编，构建出了可重定位的object文件。这些object的结构都是一样的，有各自的.text,&nbsp;.data&nbsp;section,&nbsp;有各自的.symtab.&nbsp;GCC下一步要做的就是使用linker&nbsp;(ld),把这些object文件，加上必要的库连接成具有绝对运行时地址的可执行文件，就是可执行的ELF格式的文件。<br/>&nbsp;&nbsp;&nbsp;&nbsp;Linker&nbsp;的连接动作可以分为两部分：<br/>1)&nbsp;符号解析。确定引用符号的指向。<br/>2)&nbsp;符号重定位。合并section,&#160;&#160;&#160;&#160;分配运行时环境地址，引用符号重定位。<br/>&nbsp;&nbsp;&nbsp;&nbsp;符号解析：<br/>&nbsp;&nbsp;&nbsp;&nbsp;在一个object文件中，有指令定义了符号，也有指令引用了符号。可能存在这样一种情况，一个被引用到的符号，有多重的定义。符号解析的作用就是确定，在这个object文件中，一个符号引用真正引用的是哪个符号。<br/>&nbsp;&nbsp;&nbsp;&nbsp;在编译的时候，除了在本文件中定义的全局变量会由编译器生成一个符号表项之外，当发现一个被引用到的符号在本文件中并没有被定义，编译器也会自动产生一个符号表项，把确定这些引用的工作留给linker。汇编器在汇编时将读取这些符号表项，生成.symtab。在读取的过程中，如果发现有在无法确定的符号引用项，汇编器会为这些符号额外生成一个数据项，称作重定位数据项，存放于rel.text或rel.data&nbsp;section中，交由linker确定。下面是重定位数据项（relocation&nbsp;entry）的数据结构：<br/><br/>Typedef&nbsp;struct{<br/>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;offset;//指明需要被重定位的引用在object中的偏移，实际上就是需要被重定位的引用<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//在object中的实际位置<br/>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;symbol;//这个被重定位的引用真实指向的符号<br/>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;type;//重定位类型：R_ARM_PC24:使用24bit的PC相对地址重定位引用<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&nbsp;&nbsp;//R_ARM_ABS32:使用32bit绝对地址重定位引用<br/>}Elf32_Rel<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;Linker&nbsp;需要解析的，就是那些被生成了重定位数据项的引用。Linker将根据C语言定义的规则，对于每一个重定位数据项，在输入的各个object文件中查找适合的符号，把这个符号填入symbol项中。但是由于还不知道这个符号的真实地址，所以现在就算知道了引用的真实指向，但我们还是不能确定这个引用指向的地址。<br/>&nbsp;&nbsp;&nbsp;&nbsp;符号重定位：<br/>&nbsp;&nbsp;&nbsp;&nbsp;符号重定位用来解决上面的问题。Linker首先进行section&nbsp;的合并。Linker合并object文件的过程很简单，一般就是相同属性的section合并，例如不同object文件的.text&nbsp;section&nbsp;将被合并成一个.text。同样，.symtab&nbsp;section也被合并成一个.symtab。这里面涉及到两个问题：<br/>1)&nbsp;各个object文件合并的顺序。这个问题涉及到最终指令和符号的运行地址。最为重要的是，究竟是哪个section排在最前头？在ARM&nbsp;RAW&nbsp;系统得开发过程中，这个最为重要。ARM系统CPU上电后，系统会自动的从0x00000000地址取指令并执行，这个地址上映射着存储器。这个动作是不可编程的。所以排在最前面的section一定要包含有程序的入口点，否则系统无法正常运行。<br/>2)&nbsp;输入段与输出端之间的对应关系。理论上，任何section,都可以被随意的映射到一个输出段中。一个.data&nbsp;section是可以与一个.text&nbsp;section&nbsp;组成输出一个.text的。当然这样的动作毫无意义。我们必须告诉linker使用那些section作为输入，产生一个输出section.<br/>&nbsp;&nbsp;&nbsp;&nbsp;以上这两个问题，都是通过一个称为连接脚本的文件控制的。Linker通过读取连接脚本，来决定section&nbsp;从输入到输出的映射，设置程序的入口点，设置哪个section应该在整个可执行文件的头部等问题。<br/>&nbsp;&nbsp;&nbsp;&nbsp;连接脚本还有另外一个作用，那就是指定每个section的地址。在section&nbsp;合并完成后，linker将跟据.symtab，对符号进行统一的编址，分配一个绝对的运行时地址。这个地址是以section地址作为基地址的。假设.text&nbsp;section的地址是0x00000000，那么.text里面的符号将以0x00000000这个地址作为基准地址。指定section地址的工作也是由连接脚本完成。在嵌入式开发中常见的在编译工程时需指定的text_base,&nbsp;data_base等参数，最后会被加入到连接脚本中，从而完成section的地址分配。<br/>&nbsp;&nbsp;&nbsp;&nbsp;以上两步完成后，linker&nbsp;执行引用符号重定位操作。Linker遍历.rel&nbsp;section&nbsp;(包括.rel&nbsp;text&nbsp;和&nbsp;.rel&nbsp;data)，对于其中的每个数据项，根据symbol域到.symtab&nbsp;中查出相应的引用的真实地址(经过上面的地址分配，现在.symtab里面的符号都具有绝对的运行地址)，再根据offset域提供的偏移，将这个地址填入相应的位置上。<br/>&nbsp;&nbsp;&nbsp;&nbsp;至此，符号重定位工作全部完成。Linker删除用于保存重定位信息的rel.text和rel.data&nbsp;section，加入一个segment&nbsp;header和&nbsp;一个.init&nbsp;section。生成可执行的ELF格式的object文件。<br/>&nbsp;&nbsp;&nbsp;&nbsp;Segment&nbsp;header保存了用于操作系统内存映射的信息。.init&nbsp;section&nbsp;包含了一个_init&nbsp;的函数。程序加载时，操作系统的程序加载器通过读取segment&nbsp;header，将程序加载到用户内存空间，并根据segment&nbsp;header里面映射信息，分别将.text&nbsp;段和.data段映射到适当的地址上。然后再调用.init中的_init函数，完成初始化工作。<br/>&nbsp;&nbsp;&nbsp;&nbsp;由于ELF文件具有通用性强的优点，现在流行的开发模式是，先通过编译工具生成ELF文件格式的可执行文件，在使用外部工具，抽离出ELF文件中的相应部分，生成BIN文件。例如著名的GNU&nbsp;bootloader&nbsp;U-Boot，就采用了这种做法，编译器工具集是GCC，BIN生成工具是elf2bin。ARM公司著名的开发环境ADS，虽然使用的是自家的armcc,和armcpp编译器，但他们的工作方式却是与GNU&nbsp;GCC如出一辙。<br/><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/77/Elf-layout--en.svg/200px-Elf-layout--en.svg.png" border="0" alt=""/>]]></description>
		</item>
		
</channel>
</rss>