📄 谈谈对齐(下) - fmddlmyy的专栏 - csdnblog.htm
字号:
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2008/02.aspx">2008年02月(2)</A>
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2007/11.aspx">2007年11月(1)</A>
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2007/06.aspx">2007年06月(3)</A>
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2007/04.aspx">2007年04月(2)</A>
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2007/03.aspx">2007年03月(2)</A>
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2007/02.aspx">2007年02月(3)</A>
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2006/07.aspx">2006年07月(1)</A>
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2005/09.aspx">2005年09月(5)</A>
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2005/08.aspx">2005年08月(1)</A>
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2005/06.aspx">2005年06月(1)</A>
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2005/05.aspx">2005年05月(2)</A>
<LI><A
href="http://blog.csdn.net/fmddlmyy/archive/2005/04.aspx">2005年04月(3)</A></LI></UL></DIV><SPAN
id=RecentVisitors></SPAN><SPAN id=SubscriptionList>
<DT>订阅我的博客
<DD><A href="http://blog.csdn.net/fmddlmyy/Rss.aspx"><IMG alt=XML聚合
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/xml.gif"
border=0></A> <A href="http://feeds.feedsky.com/csdn.net/fmddlmyy"
target=_blank><IMG alt=FeedSky
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/feedsky.gif" border=0></A>
<DD><A
href="http://www.xianguo.com/subscribe.php?url=http://blog.csdn.net/fmddlmyy/Rss.aspx"
target=_blank><IMG alt=订阅到鲜果
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/rss_xianguo.jpg" border=0></A>
<DD><A
href="http://fusion.google.com/add?feedurl=http://blog.csdn.net/fmddlmyy/Rss.aspx"
target=_blank><IMG alt=订阅到Google
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/rss_google.gif" border=0></A>
<DD><A
href="http://www.zhuaxia.com/add_channel.php?url=http://blog.csdn.net/fmddlmyy/Rss.aspx"
target=_blank><IMG alt=订阅到抓虾
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/rss_zhuaxia.gif" border=0></A>
<DD><A
href="http://www.bloglines.com/sub/http://blog.csdn.net/fmddlmyy/Rss.aspx"
target=_blank><IMG alt=订阅到BlogLines
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/rss_bloglines.gif" border=0></A>
<DD><A
href="http://add.my.yahoo.com/rss?url=http://blog.csdn.net/fmddlmyy/Rss.aspx"
target=_blank><IMG alt=订阅到Yahoo
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/rss_yahoo.gif" border=0></A>
<DD><A
href="http://rss.gougou.com/find_rss.jsp?url=http://blog.csdn.net/fmddlmyy/Rss.aspx"
target=_blank><IMG alt=订阅到GouGou
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/rss_gougou.gif" border=0></A>
<DD><A
href="http://www.pageflakes.com/subscribe.aspx?url=http://blog.csdn.net/fmddlmyy/Rss.aspx"
target=_blank><IMG alt=订阅到飞鸽
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/rss_pageflakes.gif" border=0></A>
<DD><A
href="http://www.rojo.com/add-subscription?resource=http://blog.csdn.net/fmddlmyy/Rss.aspx"
target=_blank><IMG alt=订阅到Rojo
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/rss_rojo.gif" border=0></A>
<DD><A
href="http://www.newsgator.com/ngs/subscriber/subfext.aspx?url=http://blog.csdn.net/fmddlmyy/Rss.aspx"
target=_blank><IMG alt=订阅到newsgator
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/rss_newsgator.gif" border=0></A>
<DD><A
href="http://www.netvibes.com/subscribe.php?url=http://blog.csdn.net/fmddlmyy/Rss.aspx"
target=_blank><IMG alt=订阅到netvibes
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/rss_netvibes.gif"
border=0></A></SPAN> </DD></DL></DIV></DIV></DIV>
<DIV id=csdnblog_content>
<DIV class=gutter>
<SCRIPT src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/PrintNotice.js"
type=text/javascript></SCRIPT>
<DIV class=default_contents>
<DIV class=user_article>
<SCRIPT src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/LoadFeedbackCount.js"
type=text/javascript></SCRIPT>
<H1><IMG height=16 alt=原创
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/authorship.gif" width=15
border=0> <A
href="http://blog.csdn.net/fmddlmyy/archive/2008/07/24/2707078.aspx">谈谈对齐(下)</A><CITE
class=fav_csdnstylebykimi><A class=fav_csdnstylebykimi title=收藏到我的网摘中,并分享给我的朋友
href="javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(saveit=window.open('http://wz.csdn.net/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'saveit','scrollbars=no,width=590,height=300,left=75,top=20,status=no,resizable=yes'));saveit.focus();">收藏</A></CITE></H1>
<DIV class=blogstory>
<SCRIPT>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</SCRIPT>
<H1>谈谈对齐(下)</H1>
<H2>3 数据对齐</H2>
<H3>3.1 CISC和RISC</H3>
<P>CPU从指令集的特点上可以分为两类:CISC和RISC。CISC和RISC分别是复杂指令集计算机(Complex Instruction Set
Computer)和精简指令集计算机(Reduced Instruction Set Computer)的缩写。</P>
<P>CPU的工作可以看作以下步骤的反复循环:</P>
<UL>
<LI>step 1: 取指令
<LI>step 2: 取数据
<LI>step 3: 执行指令
<LI>step 4: 输出结果 </LI></UL>
<P>CISC CPU支持很多寻址模式,因此取数据的时间是不确定的。 RISC
CPU的最大特点是简化了指令的寻址模式,除了Load/Store指令外,其它指令都采用寄存器寻址,即从寄存器读写数据。这种设计使取数据的时间相对稳定,可以简化指令流水线的设计。</P>
<P>一般而言,RISC架构可以降低CPU的复杂性以及允许在同样的工艺水平下生产出功能更强大的CPU,但对于编译器的设计有更高的要求。</P>
<H3>3.2 对齐数据访问</H3>
<P>RISC CPU的Load/Store指令要求数据是对齐的。长度为4的数据应放在4n边界上,长度为2的数据应放在2n边界上。以ARM
CPU的Load为例:</P><PRE>LDR R5,[R4]
LDRSH R7,[R6]
LDRB R9,[R8]
</PRE>
<P>LDR、LDRSH、LDRB分别从存储器读取一个字、半字和字节,放到指定寄存器。例如“LDR
R5,[R4]”就是从R4指向的存储单元中读一个字(长度为4),放到R5中。
LDR要求数据地址在4n边界上,否则就会发生错误。LDRSH要求数据地址在2n边界上,否则就会发生错误。</P>
<P>发生什么错误呢?这与具体的CPU有关,在ARM7TDMI上,非对齐访问会导致程序跳到数据访问错误的处理向量,即地址0x00000010处。在ARM920T上,LDR指令可能返回错误的数据。</P>
<P>CISC的CPU支持非对齐的数据读取。</P>
<H3>3.3 例子</H3>
<P>我们来看一个例子:</P><PRE>// 例子1
void test(void)
{
char a[] = {1,2,3,4,5};
int *pi, i;
printf("&a[1]=%p\n", &a[1]);
pi = (int *)&a[1];
i = *pi;
printf("%08X\n", i);
}
</PRE>
<P>关键是这句:</P><PRE> i = *pi;
</PRE>
<P>我们知道地址pi指向的4个字节依次是:0x02,0x03,0x04,0x05。在小尾的CPU上,我们期待的输出是05040302。让我们看看这段代码在不同平台的运行效果。</P>
<H4>3.3.1 PC/Windows</H4>
<P>输出结果是:</P><PRE>&a[1]=0012FF25
05040302
</PRE>
<P>符合我们的预期,也说明PC的CPU支持非对齐的数据读取。</P>
<H4>3.3.2 PC/Linux</H4>
<P>输出结果是:</P><PRE>&a[1]=0xbfa0c36c
05040302
</PRE>
<P>值得注意的是gcc编译器将局部变量a放在了1n边界(0xbfa0c36b)上。我们希望pi是一个奇数地址,将测试代码修改为:</P><PRE>// 例子2
void test(void)
{
int a[] = {0x04030201, 0x08070605};
int *pi, i;
pi = (int *)&((char *)&a)[1];
printf("pi=%p\n", pi);
i = *pi;
printf("%08X\n", i);
}
</PRE>
<P>输出结果是:</P><PRE>pi=0xbfe87fe9
05040302
</PRE>
<P>符合我们的预期。数据对齐是CPU的问题,和编译器、操作系统没有关系。</P>
<H4>3.3.3 ARM920T/Linux</H4>
<P>输出结果是:</P><PRE>&a[1]=0xbec49e55
01040302
</PRE>
<P>考虑到小尾,CPU实际读到的4个字节依次是0x02,0x03,0x04,0x01。这个结果不是我们所预期的,CPU出错了。</P>
<H4>3.3.4 ARM7TDMI</H4>
<P>程序在执行:</P><PRE> i = *pi;
</PRE>
<P>时直接跳回Data Abort的处理向量,即地址0x00000010。</P>
<H3>3.4 对策</H3>
<P>在读取紧缩结构或结构的紧缩成员时,编译器会自动产生按字节读取的代码。我们只要在做强制指针转换时细心一些就可以了。我们不应该将指向窄数据的指针强制转换成指向宽数据的指针。在可能发生数据对齐问题的地方,按字节读取数据。</P>
<H2>4 结束语</H2>
<P>我很欣赏一本叫作《玫瑰的名字》的小说。这是一本侦探小说,但给了我不少编程的启示。威廉教士在迷宫内解不开谜团,在迷宫外却推理出迷宫的真相。我也倾向于在头脑中调试程序,调试器只是不得已而用之。身陷其中,既会改变要测试的对象,也可能被表象迷惑。从外面观察,通过想象推理,有时更容易发现真相,或抓住调试的重点。本文讨论了一些与对齐相关的细节。多了解一些细节,有助于我们在头脑中形成更清晰的程序映像。
</P>
<P class="right articalinfo">发表于 @ <A title=permalink
href="http://blog.csdn.net/fmddlmyy/archive/2008/07/24/2707078.aspx">2008年07月24日
22:42:00</A>|<A title=评论
href="http://blog.csdn.net/fmddlmyy/archive/2008/07/24/2707078.aspx#FeedBack">评论(<SPAN
id=FeedbackCount_2707078>loading...</SPAN>
<SCRIPT type=text/javascript>AddFeedbackCountStack("2707078")</SCRIPT>
)</A>|<A title=编辑
href="http://writeblog.csdn.net/PostEdit.aspx?entryId=2707078">编辑</A>|<CITE
class=fav_csdnstylebykimi><A class=fav_csdnstylebykimi title=收藏到我的网摘中,并分享给我的朋友
href="javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(saveit=window.open('http://wz.csdn.net/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'saveit','scrollbars=no,width=590,height=300,left=75,top=20,status=no,resizable=yes'));saveit.focus();">收藏</A></CITE></P><SPAN
id=Post.ascx_ViewPost_PreviousAndNextEntriesDown>
<H3><A
href="http://blog.csdn.net/fmddlmyy/archive/2008/09/12/2919644.aspx">新一篇: c8解绑机的0.2版</A> | <A
href="http://blog.csdn.net/fmddlmyy/archive/2008/07/17/2668634.aspx">旧一篇: 谈谈对齐(中)</A></H3></SPAN></DIV>
<DIV id=Post.ascx_TagAd_palTagAd>
<DIV class=tagadfornews id=csdn_tag_adstyle></DIV></DIV></DIV>
<DIV class=commentslist><SPAN id=Anthem_Post.ascx_Comments_ltlComments__><SPAN
id=Post.ascx_Comments_ltlComments>
<DIV id=commentslist>
<H3>评论:没有评论。</H3></DIV></SPAN></SPAN></DIV>
<DIV class=spacecommment>
<DIV id=Anthem_Post.ascx_PostComment_CommentUpdatePanel__>
<DIV id=Post.ascx_PostComment_CommentUpdatePanel>
<FIELDSET><LEGEND>发表评论<DFN>只有登录用户才能发表评论!<A
href="http://passport.csdn.net/member/UserLogin.aspx?from=http://blog.csdn.net/fmddlmyy/archive/2008/07/24/2707078.aspx">登录</A> <A
href="http://passport.csdn.net/CSDNUserRegister.aspx">注册</A></DFN></LEGEND><EM><IMG
alt=只有登录用户才能发表评论!请登录或注册
src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/blog_commentnotice.gif"></EM>
</FIELDSET> </DIV></DIV></DIV>
<SCRIPT type=text/javascript>
LoadFeedbackCount();//加载评论
document.write("<img src='http://counter.csdn.net/pv.aspx?id=24' border=0 width=0 height=0>");// 计数器
</SCRIPT>
</DIV></DIV></DIV>
<DIV id=pubfooter>
<DL>
<DT>
<DD>Csdn Blog version 3.1a
<DD>Copyright © 吕杰 </DD></DL></DIV></DIV></FORM>
<SCRIPT src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/counter.js"
type=text/javascript></SCRIPT>
<!-- *** Vdoing Code *** -->
<SCRIPT src="谈谈对齐(下) - fmddlmyy的专栏 - CSDNBlog.files/34089.js"
type=text/javascript charset=UTF-8></SCRIPT>
<NOSCRIPT><A title="Vdoing StatsX No.34089" href="http://www.vdoing.com/"><IMG
src="" border=0></A></NOSCRIPT>
<!-- *** End of Vdoing Code *** --></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -