怀疑sourcery G++ Lite版arm-none-eabi-gcc编译错误指令
以下是在Sourcery G++ Lite版 arm-none-eabi-gcc编译arm920t CPU的情况:
typedef struct {
int count;
} atomic_t;
typedef struct {
char c1;
// atomic_t i1;
int i1;
} __attribute__((__packed__)) str_t;
volatile str_t Gstr ;
int main(void)
{
Gstr.c1 = 1;
Gstr.i1 = 0x12345678;
// Gstr.i1.count = 0x12345678;
while (1);
return 0;
}
Gstr.i1 = 0x12345678;
801c: e59f3024 ldr r3, [pc, #36] ; 8048 <main+0x48>
8020: e5932000 ldr r2, [r3]
8024: e20210ff and r1, r2, #255 ; 0xff
8028: e59f201c ldr r2, [pc, #28] ; 804c <main+0x4c>
802c: e1812002 orr r2, r1, r2
8030: e5832000 str r2, [r3]
8034: e5932004 ldr r2, [r3, #4]
8038: e3c220ff bic r2, r2, #255 ; 0xff
803c: e3822012 orr r2, r2, #18
8040: e5832004 str r2, [r3, #4]
// Gstr.i1.count = 0x12345678;
while (1);
8044: eafffffe b 8044 <main+0x44>
8048: 00010068 .word 0x00010068
804c: 34567800 .word 0x34567800
以上汇编是预料范围内的,由于int i1被packed后处于非4字节对齐的地址空间,因此对i1 = 0x12345678 的操作无法通过一个ldr完成,必须分为两部分操作,即非原子操作(无论O0~O3都是要分两部分操作)。ldr指令是要求操作地址必须四字节对齐的。
typedef struct {
int count;
} atomic_t;
typedef struct {
char c1;
atomic_t i1;
// int i1;
} __attribute__((__packed__)) str_t;
volatile str_t Gstr ;
int main(void)
{
Gstr.c1 = 1;
// Gstr.i1 = 0x12345678;
Gstr.i1.count = 0x12345678;
while (1);
return 0;
}
Gstr.i1.count = 0x12345678;
801c: e59f2014 ldr r2, [pc, #20] ; 8038 <main+0x38>
8020: e5923001 ldr r3, [r2, #1]
8024: e3a01000 mov r1, #0
8028: e59f300c ldr r3, [pc, #12] ; 803c <main+0x3c>
802c: e1813003 orr r3, r1, r3
8030: e5823001 str r3, [r2, #1]
while (1);
8034: eafffffe b 8034 <main+0x34>
8038: 00010058 .word 0x00010058
803c: 12345678 .word 0x12345678
这里出现了奇怪的现象,当结构体内再使用一个结构体后,编译结果居然有非四字节对齐的ldr指令:
8020: e5923001 ldr r3, [r2, #1] 如果支持ldr的非对齐内存操作的话,那么无论变量是否对齐int型的赋值都是原子的,既然如此为什么当定义int时O3级别的编译依旧是分两部分操作呢?从操作数上看,这种直接一步操作的操作数明显更少效率更高啊?
后来在编译选项上加-fpack-struct全局pack后这种方式编译结果也和int方式一样分两部分进行了。所以怀疑编译器编译错误指令。
编译器是Sourcery G++ Lite arm-none-eabi-gcc 是不是Lite版本的问题?