什么是执行区域和输入部分的对齐?

emb*_*guy 6 c embedded arm

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

#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()
Run Code Online (Sandbox Code Playgroud)

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

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

我不明白"overaligning代码和数据部分"的含义.有人可以帮助澄清这种运动的发生方式吗?

rua*_*akh 7

编译器自然会根据系统的需要"对齐"数据.例如,在典型的32位系统中,32位整数应始终为单个4字节字(而不是部分在一个字中,部分在下一个字中),因此它总是从4开始字节边界.(这主要与处理器上可用的指令有关.系统很可能有一条指令将一个字从存储器加载到一个寄存器中,并且更不可能有一条指令加载一个任意的四个序列邻接字节到寄存器.)

编译器通常通过在数据中引入间隙来实现这一点; 例如,在这样的系统上,structa char后跟32位int,需要8个字节:char填充三个字节的一个字节,因此int右对齐,int自身为四个字节.

要"完成"数据是为了请求比编译器自然提供的更大的对齐.例如,您可以请求在8字节边界上开始32位整数,即使在使用4字节字的系统上也是如此.(这样做的一个主要原因是,如果您的目标是使用8字节字的系统进行字节级互操作:如果将structs从一个系统传递到另一个系统,则需要两个系统中的相同间隙.)


Adr*_*Cox 5

通过overalign,Keil意味着没有比将对象与更大的对齐边界对齐而不是数据类型所需的更复杂.

请参阅__align的文档:"您只能进行操作.也就是说,您可以将两个字节的对象设置为四字节对齐,但不能将两个字节的四字节对象对齐."

对于链接器,您可以使用ALIGNALLor OVERALIGN指令强制在其他二进制模块中的部分上进行额外的对齐.出于性能原因,这可能很有用,但这不是常见的情况.


Mys*_*ial 5

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

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

过度对齐允许您将此对齐方式增加到大于默认值的程度。


至于你为什么要这样做:

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

例如:

char buffer[16];

int *ptr = (int*)&buffer;

ptr[0] = 1;
ptr[1] = 2;
Run Code Online (Sandbox Code Playgroud)

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

__align() 会让你强制对齐更高以使其工作:

 __align(4) char buffer[16];
Run Code Online (Sandbox Code Playgroud)

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