在移植一份代码时,遇到一个alignment trap的错误:
经过定位,触发alignment trap的汇编语句如下:
printk("status %#x\r\n", stData.info->status);
38c0: f8d4 3181 ldr.w r3, [r4, #385] ; 0x181
38c4: f240 2261 movw r2, #609 ; 0x261
38c8: 485d ldr r0, [pc, #372]
38ca: 9301 str r3, [sp, #4]
38cc: 4b57 ldr r3, [pc, #348]
38ce: 9200 str r2, [sp, #0]
38d0: 4619 mov r1, r3
38d2: f7ff fffe bl 0 <printk>
原因是ARM对ldr指令访问内存时要求4字节对齐,根据r4+0x181=0xd0b02181,这个地址不是4字节对齐的,所以arm触发了alignment异常。
造成这个对齐异常,与下面这个结构体的定义有关:
#pragma pack(push, 1)
struct
{
unsigned int bit_0_3 :4;
unsigned int bit_7_4 :4;
unsigned int status :32;
......
};
#pragma pack(pop)
由于使用了1字节对齐(为了节省内存),所以访问status成员时,就访问了4字节对齐偏移1字节的地址了。
解决办法
使用-mno-unaligned-access编译选项,该编译选项是 ARM 架构编译器的优化选项,用于禁止编译器生成可能导致非对齐内存访问的指令。
重新编译后对应的汇编代码:
printk("int_status %#x\r\n", stData.info->status);
3b50: f894 2182 ldrb.w r2, [r4, #386] ; 0x182
3b54: f894 3181 ldrb.w r3, [r4, #385] ; 0x181
3b58: 4879 ldr r0, [pc, #484] ; (3d40 <EncFwAnaNodeInfo+0x1618>)
3b5a: ea43 2302 orr.w r3, r3, r2, lsl #8
3b5e: f894 2183 ldrb.w r2, [r4, #387] ; 0x183
3b62: ea43 4302 orr.w r3, r3, r2, lsl #16
3b66: f894 2184 ldrb.w r2, [r4, #388] ; 0x184
3b6a: ea43 6302 orr.w r3, r3, r2, lsl #24
3b6e: f240 2261 movw r2, #609 ; 0x261
3b72: 9301 str r3, [sp, #4]
3b74: 4b6d ldr r3, [pc, #436] ; (3d2c <EncFwAnaNodeInfo+0x1604>)
3b76: 9200 str r2, [sp, #0]
3b78: 4619 mov r1, r3
3b7a: f7ff fffe bl 0 <printk>
发现之前的
ldr.w r3, [r4, #385]
变成了
ldrb.w r2, [r4, #386]
ldrb.w r3, [r4, #385]
ldrb.w r2, [r4, #387]
ldrb.w r2, [r4, #388]
这是一种以时间换空间的解决方法。