查看原文
其他

漫谈C变量——对齐(3)

GorgonMeducer 傻孩子 裸机思维 2022-10-21


【正文】



  前面的两篇文章,我们分别介绍了“为什么变量要对齐到它的尺寸大小”,“编译器会怎么处理内存的对齐问题”以及“非对齐是如何产生的和非对齐的后果”,感觉自己错过了重要内容的朋友可以发送关键字“对齐”来复习一下。下面我们来介绍几个于对齐相关的问题:


1. 结构体的对齐

  在ARM Compiler里面,结构体内的成员并不是简单的对齐到字(Word)或者半字(Half Word),更别提字节了(Byte),结构体的对齐使用以下规则:

  • 整个结构体,根据结构体内最大的那个元素来对齐。比如,整个结构体内部最大的元素是WORD,那么整个结构体就默认对齐到4字节。

  • 结构体内部,成员变量的排列顺序严格按照定义的顺序进行

  • 结构体内部,成员变量自动对齐到自己的大小——这就会导致空隙的产生。

    比如:


struct {

   uint8_t     a;

   uint16_t   b;

   uint8_t     c;

   uint32_t   d;

} Example;



  • 结构体内部,成员变量可以单独指定对齐方式为byte,例如

struct {

    uint8_t a;

    uint16_t b __attribute__ ((packed));

    uint8_t c;

    uint32_t d;

} Example;


效果就会变成:



2. Cortex-M 中断向量表的对齐

  Cortex-M中断向量表保存的都是32位的地址,每一个地址指向一个中断处理程序,因此中断向量表的大小必然是4的整倍数。理论上,你有n个中断,就因该有(n+1)*4 个字节大小的中断向量表。然而事情并非这么简单。为了硬件实现的方便


  • 中断向量表的大小必须是2^n (6<n<12) ,也就是128B,256B,512B,     1024B,2048B之一

  • 中断向量表的地址必须要对齐到它的大小,比如512Byte大小的中断向量表,其首地址必须要对齐到 0x0200(是0x200的整数倍)


  为什么会存在这样的限制呢,原因很简单,假设向量号为x的中断被触发了,Cortex-M内核就会用这个x作为下标去访问这个uint32_t的数组,那么这个中断向量具体在内存里面的地址如何计算的呢?


我们认为是这样的:

中断向量地址 = 向量表基地址    +    (x * 4)


然而,我们天真了,为了省事,这里的“+”运算被替换成了简单的"或"运算,也就是说,实际的硬件实现是这样的:

中断向量地址 = 向量表基地址    OR    (x *4)


这意味着什么呢?加法运算是会进位的!或运算不会。举例来说:

0x01 OR 0x01 = 0x01

0x01 + 0x01 = 0x02


  当硬件认为系统中向量表应该是512个字节大小时,如果向量表的基地址(通过SCB->VTOR寄存器设置)对齐到了0x0200,那么或运算的结果就与加法是等效的——原因很简单,(x * 4) 的部分不会超过0x0200,因而与加法等效。反之就有问题了。

  又由于系统强制要求中断向量表必须最少对齐到128个字节,那么对一个512字节大小的向量表来说,如果仅对齐到128个字节会发生什么呢?——如果前31个中断(包括系统自己的异常)触发了,系统可以正常处理,从第32个中断开始,任何一个触发,系统一定会出错——中断向量的所在的位置算错啦!(注意不是中断处理程序的地址算错了,是保存中断处理程序地址的那个向量所在的内存地址被算错了)


3. Cortex-M MPU 受保护内存区块的对齐

  MPU也许你听说过,但你多半没有用过,因为“太!难!用!拉!”,为了硬件实现的方便,MPU每一个Region的设置被加入了一个人为的限制:


  • Region的大小必须是  2^n (4<n<33),也就是32,64...2G, 4G

  • Region的基地址必须对齐到它的大小


  又来!是的,就是这么坑,所以如果你想用MPU保护一个任意位置任意大小的Memory,比如stack,不好意思,你要用很多个Region一起来拼接……具体怎么拼,说起来都麻烦,何况用……算了不说了。

  好消息是,最新的ARMv8-M终于改进了这个反人类的设计,允许用户通过起始地址+终止地址的方法设定任意大小任意位置的Region(当然Region大小必须是32的倍数,这个地址也必须是32的倍数)。可以好好松口气了。


————————以上正文结束———————————


如果你喜欢我的思维,欢迎订阅 裸机思维

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存