Gccarmnoneeabi 10.3.1 does behavior I didn’t expect

I recently used the gccarm tool chain to develop stm32. When compiling a freertos program, gccarm made a behavior that surprised me. It took me an entire night to find this bug.

Here is the source code of the function where the bug occurs:

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(); //In order to reduce the lock application time as much as possible, two function calls should be omitted
        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);
    }
}

As you can see, I added a static keyword in front of the variable SHT20_Wire so that the program can run normally. But according to logic, even if I don’t add this keyword, the program should still run normally.

This is the assembly code generated without adding the static keyword

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

This is the assembly code generated by adding the static keyword:

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

I don’t know assembly very well, but these two pieces of assembly code seem to show that when I don’t add the static keyword, the address of SHT20_Wire is not stored in the stack, causing the value stored at this address to be modified in the subsequent process. caused a system error

But I called the sht2x_sensor.begin function later and passed the address of SHT20_Wire in. According to my idea, the compiler should assume that there is a private variable in this class associated with this address, so this address should not be optimized. , but should save it so that subsequent function calls are normal, but this is not the case.

I asked a friend who knows a lot more about gcc than me. He said that any variable whose address is taken should not be optimized. I am also very confused as to why gcc would make such optimization. It is because of my version. Is it too low? Or is this an optimization point written in the gcc documentation?

waiting for answering