我用GCC编写了一个ARM皮质M3的程序。
我的程序导致了一个硬故障,我正在试图排除它。
GCC版本是10.3.1,但我也用旧版本(即9.2)确认了这一点。
只有在启用优化时( (-O3). )才会发生硬错误。
有问题的功能如下:
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;
}我注意到错误发生在直线上:
data[0] = d0;拆开这个,给我:
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>具体而言,冒犯的界限是:
0000f6a6: strd r2, r3, [r12]GCC生成的代码使用strd的未对齐内存地址,这在我的体系结构中是不允许的。
如何解决这个问题呢?
这是编译器的错误,还是代码混淆了GCC?
GCC身上有没有改变这种行为的旗帜?
上述函数属于外部库,因此我无法修改它。
然而,我更喜欢让GCC生成正确指令的解决方案,而不是修改代码,因为我需要确保这个bug实际上是被修复的,而且它不会潜伏在代码的其他地方。
更新
根据评论中的建议,我怀疑函数本身是用未对齐的数据调用的。
我检查了整个堆栈框架,所有以前的函数调用,我的代码不包含强制转换、缓冲区中的未对齐索引等,这与我最初设想的不同。
问题是缓冲区本身是不对齐的,因为它被定义为:
typedef struct {
uint32_t var1;
uint32_t var2;
uint8_t var3;
uint8_t buffer[BUFFER_SIZE];
uint16_t var4;
// More variables here...
} HDLC_t;(然后由外部库强制转换为uint32_t )。
在var3和buffer之间交换位置解决了这个问题。
问题是,这个结构是在一个不在我控制范围内的库中定义的。
那么,GCC能不能在图书馆之间发现这个问题,或者把数据对齐,或者警告我这个问题?
发布于 2021-10-18 14:12:18
那么,GCC能不能在图书馆之间发现这个问题,或者把数据对齐,或者警告我这个问题?
是的,它可以,它做,它必须这样做,以便符合C。如果您在默认设置下运行gcc并尝试将uint8_t指针(HDLC_t buffer成员)传递给需要uint32_t [2]的函数,则会发生这种情况。
警告:从不兼容的指针类型传递'XTEA_decrypt‘的参数2-warning兼容-指针-类型
这违反了约束,这意味着代码是无效的C,编译器已经告诉了您很多。请参阅当C编译器发现错误时,它必须做什么?,如果您希望阻止gcc C从无效的C代码中生成二进制可执行文件,您可以打开-pedantic-errors。
至于如何修复代码,如果您一直使用这个struct:memcpy,将buffer成员放入一个临时的uint32_t [2]数组中,然后将该数组传递给函数。
您也可以将struct成员声明为_Alignas(uint32_t) uint8_t buffer[100];,但是如果您可以修改结构,您最好重新安排它,因为_Alignas将插入3个浪费的填充字节。
发布于 2021-10-18 09:51:47
最简单的方法是将data对齐到8字节。
您应该声明数组如下:
__attribute__((aligned(8))) uint32_t data[2];https://stackoverflow.com/questions/69613802
复制相似问题