【问题标题】:What is overalignment of execution regions and input sections?什么是执行区域和输入部分的过度对齐?
【发布时间】:2012-01-04 19:03:20
【问题描述】:

我今天遇到了类似于以下的代码,我很好奇实际发生了什么:

#pragma pack(1)
__align(2) static unsigned char multi_array[7][24] = { 0 };
__align(2) static unsigned char another_multi_array[7][24] = { 0 };
#pragma pack()

在 Keil 编译器中搜索对 __align 关键字的引用时,我遇到了这个:

执行区域和输入部分的过度对齐 在某些情况下,您想要过度对齐代码和数据部分...如果您可以访问原始源代码,则可以在编译时使用__align(n) 关键字...

我不明白“过度对齐代码和数据部分”是什么意思。有人可以帮助澄清这种过度对齐是如何发生的吗?

【问题讨论】:

  • Overalighment 在 ARM 上可能有用。 “立即加载” (MOV) 指令无法加载整个 32 位值。相反,它可以一次加载 8 位,旋转到任何位置。出于这个原因,您的代码可能会尝试使地址以更多的零位结尾,从而使编译后的代码更容易/更快地将指针值加载到它。

标签: c embedded arm


【解决方案1】:

编译器自然会根据系统的需要“对齐”数据。例如,在典型的 32 位系统上,32 位整数应该始终是单个 4 字节字(而不是部分在一个字中,部分在下一个字中),因此它将始终以 4-字节字边界。 (这主要与处理器上可用的指令有关。系统很可能有一条指令可以将内存中的单个字加载到寄存器中,而很少有单个指令可以加载任意四个序列相邻字节到寄存器中。)

编译器通常通过在数据中引入间隙来做到这一点;例如,在这样的系统上,structchar 后跟 32 位 int 将需要八个字节:一个字节用于 char,三个字节填充符,因此 int 是右对齐,四个字节用于 int 本身。

“过度对齐”数据是要求比编译器自然提供的更大对齐。例如,您可能要求 32 位整数从 8 字节边界开始,即使在使用 4 字节字的系统上也是如此。 (这样做的一个主要原因是,如果您的目标是与使用 8 字节字的系统实现字节级互操作性:如果您将 structs 从一个系统传递到另一个系统,则您希望两者具有相同的间隙系统。)

【讨论】:

  • 那么在声明为无符号字符的多维数组的情况下(如上例),每个元素会对齐两个字节吗?
  • @embedded_guy:不,只是变量,即整个数组;因为它是一个单字节元素的数组,所以通常不需要任何对齐,但__align(2) 要求它从两字节边界开始。不可能将每个元素对齐到两个字节,因为任何使用该数组的客户端都必须知道这一点。 (声明struct 类型时,您可以对齐各个字段,因为使用struct 的任何人总是需要所有offsetofs,但对于数组,使用常规指针算法。)
  • +1 同样,我猜有人不喜欢我们的示例。您在此处给出的结构示例甚至没有引起我的注意。 :)
  • @ruakh:感谢您的帮助。这很有意义。
【解决方案2】:

所谓过度对齐,Keil 的意思就是将对象对齐到比数据类型所需更大的对齐边界更复杂。

请参阅__align 的文档:“您只能过度对齐。也就是说,您可以使 2 字节对象四字节对齐,但不能将四字节对象对齐 2 字节。”

对于链接器,您可以使用ALIGNALLOVERALIGN 指令强制对其他二进制模块中的部分进行额外对齐。出于性能原因,这可能很有用,但并不常见。

【讨论】:

    【解决方案3】:

    过度对齐是指数据的对齐方式超过其默认对齐方式。例如,一个 4 字节的int 通常具有 4 字节的默认对齐方式。 (意味着地址可以被 4 整除)

    数据类型的默认对齐方式通常(但不总是)数据类型的大小。

    过度对齐允许您将此对齐增加到比默认值更大的值。


    至于你为什么要这样做:

    这样做的一个原因是能够访问具有更大数据类型(具有更大对齐)的数据。

    例如:

    char buffer[16];
    
    int *ptr = (int*)&buffer;
    
    ptr[0] = 1;
    ptr[1] = 2;
    

    默认情况下,缓冲区只会对齐到 1 个字节。但是,int 需要 4 字节对齐。如果buffer 未对齐到 4 个字节,则会出现未对齐异常。 (AFAIK,ARM 不允许未对齐的内存访问……x86/64 通常会这样做,但会降低性能)

    __align() 将让您强制对齐以使其工作:

     __align(4) char buffer[16];
    

    在使用 SIMD 指令时也会出现类似的情况。您将使用较大的 SIMD 数据类型访问较小的数据类型 - 这可能需要更大的对齐方式。

    【讨论】:

    • 不确定谁投了反对票。我发现您的回答很有帮助,并给了它一个赞成票。
    • +1 是 int *ptr = (int*)&buffer 的好例子。 (并取消匿名投票者。)
    猜你喜欢
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-19
    相关资源
    最近更新 更多