⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arm程序由于字节对齐引起的问题深入分析 -- 众博纷纭.htm

📁 講述ARM下的字符數據對齊方式的內容
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<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>&nbsp;&nbsp;<A title=字节对齐 
href="http://blog.ednchina.com/Label/å&shy;—节对齐.aspx">字节对齐</A>&nbsp;&nbsp;<A 
title=问题 
href="http://blog.ednchina.com/Label/问题.aspx">问题</A>&nbsp;&nbsp;</P>
<H1><A 
href="http://blog.ednchina.com/cllzs/49740/message.aspx#">ARM程序由于字节对齐引起的问题深入分析</A></H1>
<P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;首先说说,什么叫对齐。如果一个数据是从偶地址开始的连续存储,那么它就是半字对齐,否则就是非半字对齐;半字对齐的特征是bit0=0,其他位为任意值。字对齐的特征是bit1=0,bit0=1,其他位为任意值。如果一个数据是以能被4 
整除的地址开始的连续存储,那么它就是字对齐,否则就是非字对齐。举例说明四字节对齐: 
对内存进行操作时,被访问的地址必须为4的倍数。如果分配到的地址的地址不是4的倍数时,CPU实际访问的地址还是按照字对齐的方式来操作。也就是自动屏蔽bit1和bit0.&nbsp;&nbsp;&nbsp; 
</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用ADS的ARM C Complier下Optimization 
Level可能引起问题,其中的一个问题就是字节对齐的问题。下面讲讲问题的现象及实质。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
当时问题的现象是:程序使用一公共变量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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
在了解问题发生的机理前,先了解QueueCreate这个函数的工作原理。QueueCreate工作原理是,首先把buf指向的内存初始化为DataQueue格式的结构体。&nbsp; 
DataQueue的结构体格式如下:<BR>typedef struct {<BR>&nbsp;&nbsp;&nbsp; 
QUEUE_DATA_TYPE&nbsp;&nbsp;&nbsp;&nbsp; 
*Out;&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>&nbsp;&nbsp;&nbsp; QUEUE_DATA_TYPE&nbsp;&nbsp;&nbsp;&nbsp; 
*In;&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>&nbsp;&nbsp;&nbsp; QUEUE_DATA_TYPE&nbsp;&nbsp;&nbsp;&nbsp; 
*End;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
/* 指向Buf的结束位置&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; 
uint16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
NData;&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>&nbsp;&nbsp;&nbsp; 
uint16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
MaxData;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
/* 队列中允许存储的数据个数 */<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 
uint8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
(* ReadEmpty)();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 
读空处理函数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
*/<BR>&nbsp;&nbsp;&nbsp; 
uint8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
(* WriteFull)();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 
写满处理函数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
*/<BR>&nbsp;&nbsp;&nbsp; QUEUE_DATA_TYPE&nbsp;&nbsp;&nbsp;&nbsp; 
*Buf;&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>} 
DataQueue;<BR>从结构体可以看出,结构体字节类型在内存分配为: 
4字节指针变量(*Out)、4字节指针变量(*In)、4字节指针变量(*End)、2字节变量NData、2字节变量MaxData、4字节函数指针变量ReadEmpty()、4字节函数指针变量(WriteFull())<BR>&nbsp;&nbsp; 
观察结构体起始地址放在非对齐时会出现什么情况。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;起始地址为0x400015c2时的由编译器分配得到的地址&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
实际操作地址<BR>*Out&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
0x400015c2~0x400015c5&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;0x40015c0~0x400015c3<BR>*In&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
0x400014c6~0x400015c9&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; 
x400014c4~0x400015c7<BR>*End&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
0x400015ca~0x400015cd&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; 
0x400015c8~0x400015cb<BR>从表中可以看出,实际操作的地址按照4字节对齐格式得到。例如,当执行*Out进行操作时,自动屏蔽bit1和bit0,因此实际发生变化的是0x40015c0~0x400015c3,而不是0x400015c2~0x400015c5,由于实际操作地址和编译器分配地址互相覆盖,当对*In操作时,会导致*Out一起变化,对*End操作时,*In也跟着变化。正是由于非对齐的原因导致创建队列和对列操作完全错误。<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
当内存起始地址为4字节对齐地址的情况时,编译器分配地址和实际地址一致,因此不存在上述问题。</P>
<P>结 论:</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
在ARM嵌入式系统中,当把一个内存区域初始化为某个结构体时,必须注意字节对齐的情况。如果该内存起始地址为非对齐地址,不仅得不到预期的结果,还可能导致一些很奇怪的让人无法理解表面问题。在C层面上不太容易观察到这些问题的实质,只有深入到汇编一层去分析程序,才可能理解这些现象的深层原因。</P>
<P>&nbsp;</P>
<P><BR>&nbsp;</P>
<P></P>
<P class=TextInfo>系统分类: <A 
href="http://blog.ednchina.com/10048/Category.aspx">ARM</A>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;用户分类: 
<A 
href="http://blog.ednchina.com/cllzs/12321/category.aspx">技术感悟</A>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;来源: 
原创&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;<A id=aRecommend 
href="http://article.ednchina.com/tools/mail.aspx?type=blog&amp;id=49740">【推荐给朋友】</A>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;<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>&nbsp;&nbsp;&nbsp;&nbsp;阅读(3001)&nbsp;&nbsp;&nbsp;&nbsp;回复(0)&nbsp;&nbsp; 
</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 + -