我最近在使用gccarm工具链开发stm32,在编译一个freertos程序的时候,由于gccarm做出了一个让我十分意外的行为,让我花了一晚上才找到这个bug
这是出现了bug的函数的源代码:
void SHT2x_Read(void *pvParameters){
SHT2x_Struct *sht2x = (SHT2x_Struct *)pvParameters;
static TwoWire SHT20_Wire = TwoWire(sht2x->SDA_Pin, sht2x->SCL_Pin);
SHT2x sht2x_sensor;
sht2x_sensor.begin(&SHT20_Wire);
while(1){
sht2x_sensor.read();
float SHT_Temp = sht2x_sensor.getTemperature(); //为了尽可能减小锁申请时间,要省去两次函数调用
float SHT_Humi = sht2x_sensor.getHumidity();
if(xSemaphoreTake(xMutex, 1000) == pdTRUE){
//do something
SHT_msg.SHT_Humi = SHT_Humi;
SHT_msg.SHT_Temp = SHT_Temp;
xSemaphoreGive(xMutex);
}
vTaskDelay(1000);
}
}
可以看到,我在变量SHT20_Wire前加了一个static关键字,如此程序才正常运行,但是按照逻辑来讲,就算我不加这个关键字,程序也应该能正常运行
这是不加static关键字产生的汇编代码
0x08006f54: 30 b5 push {r4, r5, lr}
0x08006f56: c3 b0 sub sp, #268 ; 0x10c
0x08006f58: 42 78 ldrb r2, [r0, #1]
0x08006f5a: 01 78 ldrb r1, [r0, #0]
0x08006f5c: 09 a8 add r0, sp, #36 ; 0x24
0x08006f5e: 01 f0 93 fc bl 0x8008888 <_ZN7TwoWireC2Emm>
0x08006f62: 68 46 mov r0, sp
0x08006f64: 03 f0 ca fc bl 0x800a8fc <_ZN5SHT2xC2Ev>
0x08006f68: 09 a9 add r1, sp, #36 ; 0x24
0x08006f6a: 68 46 mov r0, sp
0x08006f6c: 03 f0 a6 fd bl 0x800aabc <_ZN5SHT2x5beginEP7TwoWire>
0x08006f70: 0d e0 b.n 0x8006f8e <_Z10SHT2x_ReadPv+58>
0x08006f72: 11 4b ldr r3, [pc, #68] ; (0x8006fb8 <_Z10SHT2x_ReadPv+100>)
0x08006f74: 5d 60 str r5, [r3, #4]
0x08006f76: 1c 60 str r4, [r3, #0]
0x08006f78: 00 23 movs r3, #0
0x08006f7a: 1a 46 mov r2, r3
0x08006f7c: 19 46 mov r1, r3
0x08006f7e: 0f 48 ldr r0, [pc, #60] ; (0x8006fbc <_Z10SHT2x_ReadPv+104>)
0x08006f80: 00 68 ldr r0, [r0, #0]
0x08006f82: fe f7 46 fa bl 0x8005412 <xQueueGenericSend>
0x08006f86: 4f f4 7a 70 mov.w r0, #1000 ; 0x3e8
0x08006f8a: ff f7 a3 f8 bl 0x80060d4 <vTaskDelay>
0x08006f8e: 68 46 mov r0, sp
0x08006f90: 03 f0 28 fe bl 0x800abe4 <_ZN5SHT2x4readEv>
0x08006f94: 68 46 mov r0, sp
0x08006f96: 03 f0 17 fd bl 0x800a9c8 <_ZN5SHT2x14getTemperatureEv>
0x08006f9a: 04 46 mov r4, r0
0x08006f9c: 68 46 mov r0, sp
0x08006f9e: 03 f0 2f fd bl 0x800aa00 <_ZN5SHT2x11getHumidityEv>
0x08006fa2: 05 46 mov r5, r0
0x08006fa4: 4f f4 7a 71 mov.w r1, #1000 ; 0x3e8
0x08006fa8: 04 4b ldr r3, [pc, #16] ; (0x8006fbc <_Z10SHT2x_ReadPv+104>)
0x08006faa: 18 68 ldr r0, [r3, #0]
0x08006fac: fe f7 22 fc bl 0x80057f4 <xQueueSemaphoreTake>
0x08006fb0: 01 28 cmp r0, #1
0x08006fb2: de d0 beq.n 0x8006f72 <_Z10SHT2x_ReadPv+30>
0x08006fb4: e7 e7 b.n 0x8006f86 <_Z10SHT2x_ReadPv+50>
0x08006fb6: 00 bf nop
0x08006fb8: 80 04 lsls r0, r0, #18
0x08006fba: 00 20 movs r0, #0
0x08006fbc: 7c 04 lsls r4, r7, #17
0x08006fbe: 00 20 movs r0, #0
这是加上了static关键字产生的汇编代码:
0x08006f90: 30 b5 push {r4, r5, lr}
0x08006f92: 8b b0 sub sp, #44 ; 0x2c
0x08006f94: 1d 4b ldr r3, [pc, #116] ; (0x800700c <_Z10SHT2x_ReadPv+124>)
0x08006f96: 1b 68 ldr r3, [r3, #0]
0x08006f98: 13 f0 01 0f tst.w r3, #1
0x08006f9c: 07 d0 beq.n 0x8006fae <_Z10SHT2x_ReadPv+30>
0x08006f9e: 01 a8 add r0, sp, #4
0x08006fa0: 03 f0 dc fc bl 0x800a95c <_ZN5SHT2xC2Ev>
0x08006fa4: 1a 49 ldr r1, [pc, #104] ; (0x8007010 <_Z10SHT2x_ReadPv+128>)
0x08006fa6: 01 a8 add r0, sp, #4
0x08006fa8: 03 f0 b8 fd bl 0x800ab1c <_ZN5SHT2x5beginEP7TwoWire>
0x08006fac: 19 e0 b.n 0x8006fe2 <_Z10SHT2x_ReadPv+82>
0x08006fae: 42 78 ldrb r2, [r0, #1]
0x08006fb0: 01 78 ldrb r1, [r0, #0]
0x08006fb2: 17 48 ldr r0, [pc, #92] ; (0x8007010 <_Z10SHT2x_ReadPv+128>)
0x08006fb4: 01 f0 98 fc bl 0x80088e8 <_ZN7TwoWireC2Emm>
0x08006fb8: 14 4b ldr r3, [pc, #80] ; (0x800700c <_Z10SHT2x_ReadPv+124>)
0x08006fba: 01 22 movs r2, #1
0x08006fbc: 1a 60 str r2, [r3, #0]
0x08006fbe: 15 48 ldr r0, [pc, #84] ; (0x8007014 <_Z10SHT2x_ReadPv+132>)
0x08006fc0: 03 f0 6e fe bl 0x800aca0 <atexit>
0x08006fc4: eb e7 b.n 0x8006f9e <_Z10SHT2x_ReadPv+14>
0x08006fc6: 14 4b ldr r3, [pc, #80] ; (0x8007018 <_Z10SHT2x_ReadPv+136>)
0x08006fc8: 5d 60 str r5, [r3, #4]
0x08006fca: 1c 60 str r4, [r3, #0]
0x08006fcc: 00 23 movs r3, #0
0x08006fce: 1a 46 mov r2, r3
0x08006fd0: 19 46 mov r1, r3
0x08006fd2: 12 48 ldr r0, [pc, #72] ; (0x800701c <_Z10SHT2x_ReadPv+140>)
0x08006fd4: 00 68 ldr r0, [r0, #0]
0x08006fd6: fe f7 1c fa bl 0x8005412 <xQueueGenericSend>
0x08006fda: 4f f4 7a 70 mov.w r0, #1000 ; 0x3e8
0x08006fde: ff f7 79 f8 bl 0x80060d4 <vTaskDelay>
0x08006fe2: 01 a8 add r0, sp, #4
0x08006fe4: 03 f0 2e fe bl 0x800ac44 <_ZN5SHT2x4readEv>
0x08006fe8: 01 a8 add r0, sp, #4
0x08006fea: 03 f0 1d fd bl 0x800aa28 <_ZN5SHT2x14getTemperatureEv>
0x08006fee: 04 46 mov r4, r0
0x08006ff0: 01 a8 add r0, sp, #4
0x08006ff2: 03 f0 35 fd bl 0x800aa60 <_ZN5SHT2x11getHumidityEv>
0x08006ff6: 05 46 mov r5, r0
0x08006ff8: 4f f4 7a 71 mov.w r1, #1000 ; 0x3e8
0x08006ffc: 07 4b ldr r3, [pc, #28] ; (0x800701c <_Z10SHT2x_ReadPv+140>)
0x08006ffe: 18 68 ldr r0, [r3, #0]
0x08007000: fe f7 f8 fb bl 0x80057f4 <xQueueSemaphoreTake>
0x08007004: 01 28 cmp r0, #1
0x08007006: de d0 beq.n 0x8006fc6 <_Z10SHT2x_ReadPv+54>
0x08007008: e7 e7 b.n 0x8006fda <_Z10SHT2x_ReadPv+74>
0x0800700a: 00 bf nop
0x0800700c: 8c 04 lsls r4, r1, #18
0x0800700e: 00 20 movs r0, #0
0x08007010: 90 04 lsls r0, r2, #18
0x08007012: 00 20 movs r0, #0
0x08007014: 31 6f ldr r1, [r6, #112] ; 0x70
0x08007016: 00 08 lsrs r0, r0, #32
0x08007018: 84 04 lsls r4, r0, #18
0x0800701a: 00 20 movs r0, #0
0x0800701c: 80 04 lsls r0, r0, #18
0x0800701e: 00 20 movs r0, #0
我不是很懂汇编,但是这两段汇编代码似乎表明,当我不加上static关键字的时候,SHT20_Wire的地址没有被存入栈中,致使这个地址存放的值在之后的进程中被修改,造成了系统错误
但是我在后面调用了sht2x_sensor.begin函数并将SHT20_Wire的地址传进去,按我的想法来说,编译器应该假设这个类中存在私有变量和这个地址相关联,如此则不应该把这个地址优化掉,而是应该把他保存起来,使之后的函数调用是正常的,但事实却不是这样
我问了问一个比我懂gcc多很多的朋友,他说凡是被取地址的变量,按理来说,不应该被优化,我也相当疑惑为什么gcc会做出这样的优化,是因为我的版本太低吗?还是说这是被写在gcc文档中的优化点吗?
等待回答ing