3

我正在使用 ARM 编译器并有一个硬件外围设备(具有直接内存访问),它需要对传递给它的内存缓冲区进行特定对齐(32 字节对齐)。aligned当缓冲区是全局/静态的并且可以使用编译器支持的属性来定义时,这不是问题。只要需要在本地传递某个函数中定义的缓冲区,即具有自动存储类,就会出现问题。我试图做类似以下的事情:

typedef struct  __attribute__((aligned(32)))
{
    char bytes[32];
} aligned_t;

_Static_assert(sizeof(aligned_t)==32, "Bad size");

void foo(void)
{
    aligned_t alignedArray[NEEDED_SIZE/sizeof(aligned_t)];
    //.... use alignedArray
}

这很高兴地编译并在x86编译器上工作。但不是在armcc,这是抱怨:

警告:#1041-D:自动对象的对齐方式不得大于 8

所以这种方法行不通。还有一个,我认为很丑:

void foo(void)
{
    char unalignedBuffer[NEEDED_SIZE + 32 - 1];
    char pAlignedBuffer = ALIGN_UP_32(unalignedBuffer);
    //.... use pAlignedBuffer
}

虽然ALIGN_UP_32是一个宏,用于返回其中的第一个对齐地址unalignedBuffer(我猜这里的实现细节并不重要)。

正如我所说,我不喜欢这种方法,想知道是否有更优雅的方法来实现同样的效果?

4

2 回答 2

2

我正在使用 ARM 编译器

您是否也尝试过最近的 GCC(可能配置为交叉编译器),例如 2018 年 11 月的 GCC 8?

ARM ABI 不保证堆栈指针(可能)与 32 字节对齐。

因此,任何自动变量都不会像您想要的那样对齐。

您可以避免它们(并系统地使用适当对齐的堆内存区域)。或者你可以分配比需要更多的东西并对其进行指针运算。

我觉得你char* pAlignedBuffer = ALIGN_UP_32(unalignedBuffer);的方法很好,我相信优化编译器会生成非常有效的代码。

我不喜欢这种方法,想知道是否有更优雅的方法来实现同样的效果?

我相信你的方法很好,任何其他方式都是等效的。

PS。另一种方法可能是修补您的 GCC 编译器(可能使用插件)以更改堆栈指针的默认对齐方式(因此有效地更改您的ABI调用约定)。这将花费您数周(或数月)的努力。

于 2018-11-29T15:36:38.280 回答
1

您的两个选项看起来是最简单的。但是(只是猜测,我对自己的答案没有太多考虑),另一种选择可能是创建另一个堆栈。当包含缓冲区的函数被执行时,上下文被切换(好吧,只是 SP - 在超级用户模式下 - ),现在 SP 指向第二个堆栈。这个堆栈分配在一个 32 位对齐的部分,它只包含 32 位对齐的对象,所以当一个本地 32 位对齐的变量被创建时,它将被分配在一个 32 位对齐的内存堆中,一旦变量超出范围,就会被释放. 一旦函数被执行,SP 就会切换回主堆栈。必须将函数的执行视为关键区域,以避免在错误的堆栈中推入/弹出。我不认为这会产生堆栈溢出,

于 2018-11-29T16:59:28.237 回答