简体   繁体   English

ARM GCC 产生未对齐的 STRD

[英]ARM GCC produces unaligned STRD

I am using GCC to compile a program for an ARM Cortex M3.我正在使用 GCC 为 ARM Cortex M3 编译程序。
My program results in a hardfault, and I am trying to troubleshoot it.我的程序导致出现硬故障,我正在尝试对其进行故障排除。

GCC version is 10.3.1 but I have confirmed this with older versions too (ie 9.2 ). GCC 版本是10.3.1但我也用旧版本(即9.2 )确认了这一点。

The hardfault occurs only when optimizations are enabled ( -O3 ).只有在启用优化 ( -O3 ) 时才会发生硬故障。

The problematic function is the following:有问题的函数如下:

void XTEA_decrypt(XTEA_t * xtea, uint32_t data[2])
{
    uint32_t d0 = data[0];
    uint32_t d1 = data[1];
    uint32_t sum = XTEA_DELTA * XTEA_NUMBER_OF_ROUNDS;

    for (int i = XTEA_NUMBER_OF_ROUNDS; i != 0; i--)
    {
        d1 -= (((d0 << 4) ^ (d0 >> 5)) + d0) ^ (sum + xtea->key[(sum >> 11) & 3]);
        sum -= XTEA_DELTA;
        d0 -= (((d1 << 4) ^ (d1 >> 5)) + d1) ^ (sum + xtea->key[sum & 3]);
    }

    data[0] = d0;
    data[1] = d1;
}

I noticed that the fault happens in line:我注意到故障发生在:

    data[0] = d0;

Disassembling this, gives me:拆开这个,给我:

49          data[0] = d0;
0000f696:   lsrs    r0, r3, #5
0000f698:   eor.w   r0, r0, r3, lsl #4
0000f69c:   add     r0, r3
0000f69e:   ldr.w   r12, [sp, #4]
0000f6a2:   eors    r5, r0
0000f6a4:   subs    r2, r2, r5
0000f6a6:   strd    r2, r3, [r12]
0000f6aa:   add     sp, #12
0000f6ac:   ldmia.w sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
0000f6b0:   ldr     r3, [sp, #576]  ; 0x240
0000f6b2:   b.n     0xfda4 <parseNode+232>

And the offending line is specifically:违规行特别是:

0000f6a6:   strd    r2, r3, [r12]

GCC generates code that uses an unaligned memory address with strd , which is not allowed in my architecture. GCC 生成的代码使用带有strd的未对齐内存地址,这在我的架构中是不允许的。

How can this issue be fixed?如何解决这个问题?
Is this a compiler bug, or the code somehow confuses GCC?这是编译器错误,还是代码以某种方式混淆了 GCC?
Is there any flag to alter this behavior in GCC?在 GCC 中是否有任何标志可以改变这种行为?

The aforementioned function belongs to an external library, so I cannot modify it.上述函数属于外部库,所以我无法修改它。
However, I prefer a solution that makes GCC produce the correct instructions, instead of modifying the code, as I need to ensure that this bug will actually be fixed, and it is not lurking elsewhere in the code.然而,我更喜欢一个让 GCC 产生正确指令的解决方案,而不是修改代码,因为我需要确保这个错误实际上会被修复,并且它不会潜伏在代码的其他地方。


UPDATE更新
Following the recommendations in the comments, I was suspecting that the function itself is called with unaligned data.按照评论中的建议,我怀疑函数本身是用未对齐的数据调用的。

I checked the whole stack frame, all previous function calls, and my code does not contain casts, unaligned indexes in buffers etc, in contrast to what I had in mind initially.我检查了整个堆栈框架,所有以前的函数调用,并且我的代码不包含强制转换、缓冲区中未对齐的索引等,这与我最初想到的相反。

The problem is that the buffer itself is unaligned, as it is defined as:问题是缓冲区本身是未对齐的,因为它被定义为:

typedef struct {
    uint32_t var1;
    uint32_t var2;
    uint8_t var3;
    uint8_t buffer[BUFFER_SIZE];
    uint16_t var4;
    // More variables here...
} HDLC_t;

(And later cast to uint32_t by the external library). (后来被外部库转换为uint32_t )。

Swapping places between var3 and buffer solves the issue.var3buffer之间交换位置解决了这个问题。

The thing is that again this struct is defined in a library that is not in my control.问题是,这个结构又是在一个不受我控制的库中定义的。

So, can GCC detect this issue between the libraries, and either align the data, or warn me of the issue?那么,GCC 能否检测到库之间的这个问题,并对齐数据或警告我这个问题?

So, can GCC detect this issue between the libraries, and either align the data, or warn me of the issue?那么,GCC 能否检测到库之间的这个问题,并对齐数据或警告我这个问题?

Yes it can, it does and it must do in order to be C compliant.是的,它可以,它确实并且必须这样做才能符合 C 标准。 This is what happens if you run gcc at default settings and attempt to pass a uint8_t pointer ( HDLC_t buffer member) to a function expecting a uint32_t [2] :如果您在默认设置下运行 gcc 并尝试将uint8_t指针( HDLC_t buffer成员)传递给需要uint32_t [2]的函数,则会发生这种情况:

warning: passing argument 2 of 'XTEA_decrypt' from incompatible pointer type [-Wincompatible-pointer-types]警告:从不兼容的指针类型 [-Wincompatible-pointer-types] 传递“XTEA_decrypt”的参数 2

This is a constraint violation, meaning that the code is invalid C and the compiler already told you as much.这是一个约束违规,意味着代码是无效的 C 并且编译器已经告诉你了。 See What must a C compiler do when it finds an error?请参阅C 编译器发现错误时必须做什么? You could turn on -pedantic-errors if you wish to block gcc C from generating a binary executable out of invalid C code.如果您希望阻止 gcc C 从无效的 C 代码中生成二进制可执行文件,您可以打开-pedantic-errors

As for how to fix the code if you are stuck with that struct : memcpy the buffer member into a temporary uint32_t [2] array and then pass that one to the function.至于如果您坚持使用该struct ,如何修复代码:将buffer成员memcpy放入临时uint32_t [2]数组,然后将其传递给函数。

You could also declare the struct member as _Alignas(uint32_t) uint8_t buffer[100];您还可以将结构成员声明为_Alignas(uint32_t) uint8_t buffer[100]; but if you can modify the struct you might as well re-arrange it instead, since _Alignas will insert 3 wasteful padding bytes.但是如果您可以修改结构体,您不妨重新排列它,因为_Alignas将插入 3 个浪费的填充字节。

The easiest way is to align data to 8bytes.最简单的方法是将data对齐到 8 字节。
You should declare the array like:您应该像这样声明数组:

__attribute__((aligned(8))) uint32_t data[2];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM