📄 arm程序由于字节对齐引起的问题深入分析 -- 众博纷纭.htm
字号:
<DIV class=digg id=ctl00_ctl00_SkinBody_Content_ContentControl_ctl00_Digg2>
<H4 id=ctl00_ctl00_SkinBody_Content_ContentControl_ctl00_Digg2_display
style="opacity: 1">1 </H4><SPAN class=unclicked onmouseover=Digg_Mouseover(this)
onclick="if(this.className != 'clicked'){WebForm_DoCallback('ctl00$ctl00$SkinBody$Content$ContentControl$ctl00$Digg2',null,DiggClientCallBack,null,null,true)}"
onmouseout=Digg_Mouseout(this)></SPAN></DIV>
<DIV class=simpleblank><A title=察看所有博客精华文章
href="http://blog.ednchina.com/cool.aspx"><IMG
id=ctl00_ctl00_SkinBody_Content_ContentControl_ctl00_imgEssent
style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px"
src=""> </A></DIV></DIV>
<DIV class=Text>
<P class=Label>标签: <A title=ARM
href="http://blog.ednchina.com/Label/ARM.aspx">ARM</A> <A title=字节对齐
href="http://blog.ednchina.com/Label/å­è对é½.aspx">字节对齐</A> <A
title=问题
href="http://blog.ednchina.com/Label/é®é¢.aspx">问题</A> </P>
<H1><A
href="http://blog.ednchina.com/cllzs/49740/message.aspx#">ARM程序由于字节对齐引起的问题深入分析</A></H1>
<P>
<P> 首先说说,什么叫对齐。如果一个数据是从偶地址开始的连续存储,那么它就是半字对齐,否则就是非半字对齐;半字对齐的特征是bit0=0,其他位为任意值。字对齐的特征是bit1=0,bit0=1,其他位为任意值。如果一个数据是以能被4
整除的地址开始的连续存储,那么它就是字对齐,否则就是非字对齐。举例说明四字节对齐:
对内存进行操作时,被访问的地址必须为4的倍数。如果分配到的地址的地址不是4的倍数时,CPU实际访问的地址还是按照字对齐的方式来操作。也就是自动屏蔽bit1和bit0.
</P>
<P> 用ADS的ARM C Complier下Optimization
Level可能引起问题,其中的一个问题就是字节对齐的问题。下面讲讲问题的现象及实质。</P>
<P>
当时问题的现象是:程序使用一公共变量Buf创建队列,如果ADS编译优化选项采用Minium则软件工作正常;源码不变,如果采用ALL优化,则不正常,数据紊乱且无法工作。为了发现问题,我们分别用Minium和ALL编译,在反汇编条件下单步跟踪程序,观察CPU寄存器和内存变量的变化情况。发现在Minium模式下,编译器把队列内存块Uart0TxBuf分配到的地址是0x400015cc,这个地址是一个4字节对齐的地址,而在ALL模式下,编译器把Buf分配的地址是0x400015c2,这个地址是一个非4字节对齐的地址。正是由于这个非4字节对齐的地址导致了问题的发生。<BR>问题发生在QueueCreate(void
*Buf, uint32 SizeOfBuf, uint8 (* ReadEmpty)(), uint8 (*
WriteFull)())这个函数里,问题是如何发生的,</P>
<P><BR>
在了解问题发生的机理前,先了解QueueCreate这个函数的工作原理。QueueCreate工作原理是,首先把buf指向的内存初始化为DataQueue格式的结构体。
DataQueue的结构体格式如下:<BR>typedef struct {<BR>
QUEUE_DATA_TYPE
*Out;
/* 指向数据输出位置
*/<BR> QUEUE_DATA_TYPE
*In;
/* 指向数据输入位置
*/<BR> QUEUE_DATA_TYPE
*End;
/* 指向Buf的结束位置 */<BR>
uint16
NData;
/* 队列中数据个数
*/<BR>
uint16
MaxData;
/* 队列中允许存储的数据个数 */<BR> <BR>
uint8
(* ReadEmpty)(); /*
读空处理函数
*/<BR>
uint8
(* WriteFull)(); /*
写满处理函数
*/<BR> QUEUE_DATA_TYPE
*Buf;
/* 存储数据的空间 */<BR>}
DataQueue;<BR>从结构体可以看出,结构体字节类型在内存分配为:
4字节指针变量(*Out)、4字节指针变量(*In)、4字节指针变量(*End)、2字节变量NData、2字节变量MaxData、4字节函数指针变量ReadEmpty()、4字节函数指针变量(WriteFull())<BR>
观察结构体起始地址放在非对齐时会出现什么情况。</P>
<P> 起始地址为0x400015c2时的由编译器分配得到的地址
实际操作地址<BR>*Out
0x400015c2~0x400015c5 0x40015c0~0x400015c3<BR>*In
0x400014c6~0x400015c9
x400014c4~0x400015c7<BR>*End
0x400015ca~0x400015cd
0x400015c8~0x400015cb<BR>从表中可以看出,实际操作的地址按照4字节对齐格式得到。例如,当执行*Out进行操作时,自动屏蔽bit1和bit0,因此实际发生变化的是0x40015c0~0x400015c3,而不是0x400015c2~0x400015c5,由于实际操作地址和编译器分配地址互相覆盖,当对*In操作时,会导致*Out一起变化,对*End操作时,*In也跟着变化。正是由于非对齐的原因导致创建队列和对列操作完全错误。<BR>
当内存起始地址为4字节对齐地址的情况时,编译器分配地址和实际地址一致,因此不存在上述问题。</P>
<P>结 论:</P>
<P>
在ARM嵌入式系统中,当把一个内存区域初始化为某个结构体时,必须注意字节对齐的情况。如果该内存起始地址为非对齐地址,不仅得不到预期的结果,还可能导致一些很奇怪的让人无法理解表面问题。在C层面上不太容易观察到这些问题的实质,只有深入到汇编一层去分析程序,才可能理解这些现象的深层原因。</P>
<P> </P>
<P><BR> </P>
<P></P>
<P class=TextInfo>系统分类: <A
href="http://blog.ednchina.com/10048/Category.aspx">ARM</A> | 用户分类:
<A
href="http://blog.ednchina.com/cllzs/12321/category.aspx">技术感悟</A> | 来源:
原创 | <A id=aRecommend
href="http://article.ednchina.com/tools/mail.aspx?type=blog&id=49740">【推荐给朋友】</A> | <A
id=ctl00_ctl00_SkinBody_Content_ContentControl_ctl00_lbAddFavourite
href="javascript:__doPostBack('ctl00$ctl00$SkinBody$Content$ContentControl$ctl00$lbAddFavourite','')">【添加到收藏夹】</A>
</P></DIV>
<DIV class=clear></DIV></DIV>
<DIV
class=DiaryInfo> 阅读(3001) 回复(0)
</DIV></DIV><!--投票-->
<DIV style="DISPLAY: none; PADDING-BOTTOM: 10px">
<P><A href="http://blog.ednchina.com/cllzs/49740/"><IMG
src="ARM程序由于字节对齐引起的问题深入分析 -- 众博纷纭.files/vote.gif" align=absMiddle></A><SPAN
style="PADDING-LEFT: 15px">投一票您将和博主都有获奖机会!</SPAN></P></DIV>
<DIV id=Comment>
<DIV id=CommentTitle>
<H2 style="FLOAT: left">最新评论 </H2></DIV>
<DIV class=Content>
<UL></UL></DIV>
<DIV class=FillIn><A name=feedback>
<TABLE id=simplyreply style="MARGIN-LEFT: 30px">
<TBODY>
<TR>
<TD><SPAN style="MARGIN-RIGHT: 30px">标题</SPAN> <SPAN><INPUT
id=ctl00_ctl00_SkinBody_Content_SimplyReplyControl_SubjectControl
style="WIDTH: 350px" value=re:ARM程序由于字节对齐引起的问题深入分析
name=ctl00$ctl00$SkinBody$Content$SimplyReplyControl$SubjectControl></SPAN>
</TD></TR>
<TR>
<TD><SPAN style="MARGIN-RIGHT: 30px">姓名</SPAN> <SPAN><INPUT
id=ctl00_ctl00_SkinBody_Content_SimplyReplyControl_UserNameControl
style="WIDTH: 350px"
name=ctl00$ctl00$SkinBody$Content$SimplyReplyControl$UserNameControl></SPAN>
<SPAN
id=ctl00_ctl00_SkinBody_Content_SimplyReplyControl_RequiredFieldValidator2
style="VISIBILITY: hidden; COLOR: red">必填</SPAN> </TD></TR>
<TR>
<TD><SPAN style="MARGIN-RIGHT: 30px">主页</SPAN> <SPAN><INPUT
id=ctl00_ctl00_SkinBody_Content_SimplyReplyControl_HomePageControl
style="WIDTH: 350px"
name=ctl00$ctl00$SkinBody$Content$SimplyReplyControl$HomePageControl></SPAN>
</TD></TR>
<TR>
<TD style="PADDING-LEFT: 64px"><TEXTAREA id=ctl00_ctl00_SkinBody_Content_SimplyReplyControl_ContentControl style="WIDTH: 350px; HEIGHT: 200px" name=ctl00$ctl00$SkinBody$Content$SimplyReplyControl$ContentControl></TEXTAREA>
</TD></TR>
<TR>
<TD><SPAN style="MARGIN-LEFT: 11px">验证码:</SPAN><INPUT
id=ctl00_ctl00_SkinBody_Content_SimplyReplyControl_EnterCodeControl
style="WIDTH: 50px" maxLength=4
name=ctl00$ctl00$SkinBody$Content$SimplyReplyControl$EnterCodeControl>
<IMG id=ctl00_ctl00_SkinBody_Content_SimplyReplyControl_DisplayCodeControl
style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px"
src="ARM程序由于字节对齐引起的问题深入分析 -- 众博纷纭.files/ValidateCode.gif"> <SPAN
id=ctl00_ctl00_SkinBody_Content_SimplyReplyControl_ValidateCodeControl
style="VISIBILITY: hidden; COLOR: red">验证码不正确</SPAN> </TD></TR>
<TR>
<TD><INPUT id=ctl00_ctl00_SkinBody_Content_SimplyReplyControl_Button1 onclick='javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("ctl00$ctl00$SkinBody$Content$SimplyReplyControl$Button1", "", true, "Post", "", false, false))' type=submit value=" 提 交 " name=ctl00$ctl00$SkinBody$Content$SimplyReplyControl$Button1>
</TD></TR></TBODY></TABLE></A></DIV></DIV></DIV></DIV></DIV>
<SCRIPT src="ARM程序由于字节对齐引起的问题深入分析 -- 众博纷纭.files/Relation.htm"
type=text/javascript></SCRIPT>
<DIV style="CLEAR: both"></DIV></DIV><!--结束--></DIV>
<SCRIPT type=text/javascript>
//<![CDATA[
var Page_Validators = new Array(document.getElementById("ctl00_ctl00_SkinBody_Content_SimplyReplyControl_RequiredFieldValidator2"), document.getElementById("ctl00_ctl00_SkinBody_Content_SimplyReplyControl_ValidateCodeControl"));
//]]>
</SCRIPT>
<SCRIPT type=text/javascript>
//<![CDATA[
var ctl00_ctl00_SkinBody_Content_SimplyReplyControl_RequiredFieldValidator2 = document.all ? document.all["ctl00_ctl00_SkinBody_Content_SimplyReplyControl_RequiredFieldValidator2"] : document.getElementById("ctl00_ctl00_SkinBody_Content_SimplyReplyControl_RequiredFieldValidator2");
ctl00_ctl00_SkinBody_Content_SimplyReplyControl_RequiredFieldValidator2.controltovalidate = "ctl00_ctl00_SkinBody_Content_SimplyReplyControl_UserNameControl";
ctl00_ctl00_SkinBody_Content_SimplyReplyControl_RequiredFieldValidator2.errormessage = "必填";
ctl00_ctl00_SkinBody_Content_SimplyReplyControl_RequiredFieldValidator2.validationGroup = "Post";
ctl00_ctl00_SkinBody_Content_SimplyReplyControl_RequiredFieldValidator2.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
ctl00_ctl00_SkinBody_Content_SimplyReplyControl_RequiredFieldValidator2.initialvalue = "";
var ctl00_ctl00_SkinBody_Content_SimplyReplyControl_ValidateCodeControl = document.all ? document.all["ctl00_ctl00_SkinBody_Content_SimplyReplyControl_ValidateCodeControl"] : document.getElementById("ctl00_ctl00_SkinBody_Content_SimplyReplyControl_ValidateCodeControl");
ctl00_ctl00_SkinBody_Content_SimplyReplyControl_ValidateCodeControl.controltovalidate = "ctl00_ctl00_SkinBody_Content_SimplyReplyControl_EnterCodeControl";
ctl00_ctl00_SkinBody_Content_SimplyReplyControl_ValidateCodeControl.validationGroup = "Post";
//]]>
</SCRIPT>
<SCRIPT type=text/javascript>
//<![CDATA[
var Page_ValidationActive = false;
if (typeof(ValidatorOnLoad) == "function") {
ValidatorOnLoad();
}
function ValidatorOnSubmit() {
if (Page_ValidationActive) {
return ValidatorCommonOnSubmit();
}
else {
return true;
}
}
theForm.oldSubmit = theForm.submit;
theForm.submit = WebForm_SaveScrollPositionSubmit;
theForm.oldOnSubmit = theForm.onsubmit;
theForm.onsubmit = WebForm_SaveScrollPositionOnSubmit;
WebForm_InitCallback();//]]>
</SCRIPT>
</FORM><!-- 统计必备 -->
<SCRIPT type=text/javascript>
var referrer = document.referrer;
var url = "<scr"+"ipt type=\"text/javascript\" src=\"http://www.ednchina.com/Statistics.aspx?list="+escape(ad_list)+"&referer="+referrer+"\"></script\>";
document.write(url);
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
try {
var pageTracker = _gat._getTracker("UA-115730-2");
pageTracker._trackPageview();
} catch (err) { }
</SCRIPT>
<!-- 统计必备 --></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -