ARM下的对齐处理   
from DUI0067D_ADS1_2_CompLib

3.13 type  qulifiers

有部分摘自ARM编译器文档对齐部分  
对齐的使用:  
1.__align(num)  
   这个用于修改最高级别对象的字节边界。在汇编中使用LDRD或者STRD时  
   就要用到此命令__align(8)进行修饰限制,来保证数据对象是相应对齐。  
   这个修饰对象的命令最大是8个字节限制,可以让2字节的对象进行4字节  
   对齐,但是不能让4字节的对象2字节对齐。  
   __align是存储类修改,他只修饰最高级类型对象,不能用于结构或者函数对象。

比如:__align(4) u8 mem1base[MEM1_MAX_SIZE];//保证分配的数组空间4字节对齐,同时保证数组首地址可被4整除
     
2.__packed   
  __packed是进行一字节对齐  
  1.不能对packed的对象进行对齐  
  2.所有对象的读写访问都进行非对齐访问  
  3.float及包含float的结构联合及未用__packed的对象将不能字节对齐  
  4.__packed对局部整形变量无影响  
  5.强制由unpacked对象向packed对象转化是未定义,整形指针可以合法定  
  义为packed。  
     __packed int* p;  //__packed int 则没有意义  
  6.对齐或非对齐读写访问带来问题  
  __packed struct STRUCT_TEST  
{  
  char a;  
  int b;  
  char c;  
}  ;    //定义如下结构此时b的起始地址一定是不对齐的  
         //在栈中访问b可能有问题,因为栈上数据肯定是对齐访问[from CL]  
//将下面变量定义成全局静态不在栈上   
static char* p;  
static struct STRUCT_TEST a;  
void Main()  
{  
__packed int* q;  //此时定义成__packed来修饰当前q指向为非对齐的数据地址下面的访问则可以

p = (char*)&a;            
q = (int*)(p+1);

*q = 0x87654321;   
/*     
得到赋值的汇编指令很清楚  
ldr      r5,0x20001590 ; = #0x12345678  
[0xe1a00005]   mov      r0,r5  
[0xeb0000b0]   bl       __rt_uwrite4  //在此处调用一个写4byte的操作函数   
        
[0xe5c10000]   strb     r0,[r1,#0]   //函数进行4次strb操作然后返回保证了数据正确的访问  
[0xe1a02420]   mov      r2,r0,lsr #8  
[0xe5c12001]   strb     r2,[r1,#1]  
[0xe1a02820]   mov      r2,r0,lsr #16  
[0xe5c12002]   strb     r2,[r1,#2]  
[0xe1a02c20]   mov      r2,r0,lsr #24  
[0xe5c12003]   strb     r2,[r1,#3]  
[0xe1a0f00e]   mov      pc,r14  
*/

/*  
如果q没有加__packed修饰则汇编出来指令是这样直接会导致奇地址处访问失败  
[0xe59f2018]   ldr      r2,0x20001594 ; = #0x87654321  
[0xe5812000]   str      r2,[r1,#0]  
*/

//这样可以很清楚的看到非对齐访问是如何产生错误的  
//以及如何消除非对齐访问带来问题  
//也可以看到非对齐访问和对齐访问的指令差异导致效率问题  
}

比如:

typedef __packed struct READ_Command
{
    u_char code;
    u_int addr;
    u_char len;
} READ_Command;

typedef  struct READ_Command
{
    u_char code;
    u_int addr;
    u_char len;
} READ_Command;
的区别是什么啊?
回答:没有__packed的会出现字对齐等也就是,char型的有可能是占用4个字节的长度的内存空间有__packed 的就不会,就肯定是1个字节的内存空间,是gcc编译器的关键字。(不止vc下面32位的系统里面的内存数据的存取是32位的,处理的时候都是4个字节为单位,通常也就是int的长度。如果不定义压缩方式,也就是编译选项没有诸如#pragma pack(1)之类的,那么系统会进行4字节对齐)
注意:_packed只是某种编译器的格式压缩,有的是pack呢,对不同的CPU压缩的对齐方式也不一样,在使用了该关键以后在进行操作时需要格外小心。
声明结构类型时,可以包含一个保留字packed,用于实现压缩数据存储。
      当一个记录类型在   {$A-}   状态下声明或者声明中包括了保留字   packed   时,记录中的字段不被调整,而替换为赋予连续的偏移量。这样一个压缩记录的总尺寸就是所有字段的尺寸的和。因为数据调整尺寸可能改变(如不同版本的编译器对同一种数据类型的调整值可能不同),所以当想要把记录写入磁盘时或者在内存中传递到另一模块而该模块由不同版本的编译器编译时,最好还是压缩所有的记录。(delphi borland 中也有该关键字)
 
3.在 Cotex-M3 programming manual 中有提到对齐问题
  1.通常编译器在生成代码的时候都会进行结构体填充,保证(结构体内部成员)最高性能的对齐方式。
  2.编译器自动分配出来结构体的内存(比如定义为全局变量或局部变量)肯定是对齐的。
  3.查阅帮助文档的malloc部分,mdk的标准malloc申请的内存区时8字节对齐的。
  4.若自定义的malloc函数本身没有对分配的内存实现4字节或以上的对齐操作,分配出来的不对齐的内存,编译器是不知道的,所以很可能会产生问题。
     此时最好的解决方式在内存池数组前添加__align(4)关键字,只需保证自定义malloc分配出来的首地址是4字节对齐。
     比如:__align(4) u8 mem1base[MEM1_MAX_SIZE];
 
相关更多stm32字节对齐问题的讨论,请参考正点原子相关帖子http://www.openedv.com/thread-7415-1-1.html。
其中问题的关键就在于正点原子自定义的mymalloc函数没有实现4字节对齐。

最新文章

  1. CoreCRM 开发实录——Travis-CI 实现 .NET Core 程度在 macOS 上的构建和测试 [无水干货]
  2. C#操作图片帮助类
  3. python 3次登录
  4. list的一些使用
  5. 如何在Visual Studio 2013中使用Ribbon For WPF
  6. GIS 学习及参考站点
  7. Oracle由ID生成父ID的函数
  8. JSP控制select不可再选择
  9. java基础知识再学习--HashMap与ConcurrentHashMap的区别
  10. Linux文件属性及如何修改文件属性
  11. js 作用域,作用域链,闭包
  12. 基于.net的通用内存缓存模型组件
  13. 【CSS3】盒模型
  14. RobotFramework下的http接口自动化post关键字的使用
  15. JdbcTemplate源码解析
  16. django源码分析 LazySetting对象
  17. Oracle查询数据库中所有表的记录数
  18. 构造方法关键字---this
  19. ORM操作 数据库外键 一对多
  20. 重定向printf

热门文章

  1. 拯救大兵瑞恩 HDU - 4845(状压bfs || 分层最短路)
  2. 一个死循环导致的栈溢出实例:StackOverFlowError
  3. day27 多态 多继承 接口类 抽象类
  4. Change upload file limit in specified Webapllication in SharePoint (PowerShell)
  5. 洛谷 P4148 简单题 解题报告
  6. py3+urllib+bs4+反爬,20+行代码教你爬取豆瓣妹子图
  7. luogu1972 HH的项链(树状数组)
  8. luogu4849 寻找宝藏 (cdq分治+dp)
  9. 【codeforces 768F】 Barrels and boxes
  10. 使用“DiskGenius”精确隐藏硬盘坏道