对于GCC单片机的编译行为,我对32位值的其他功能有一些误解。
MCU: STM32 L0 Series (STM32L083)
GCC : gcc version 7.3.1 20180622 (release) [ARM/embedded-7-branch revision 261907] (GNU Tools for Arm Embedded Processors 7-2018-q2-update)我的代码是针对大小进行优化的(使用选项-Os )。根据我的理解,这将允许gcc使用隐式-fshort-enums来打包枚举。
我有两个枚举变量,1字节宽:
enum eRadioMode radio_mode // (@ 0x20003200)
enum eRadioFunction radio_func // (@ 0x20003201)和一项职能:
enum eRadioMode radio_get_mode(enum eRadioFunction _radio_func);当我把这堆代码叫做:
radio_mode = radio_get_mode(radio_func);它将在编译时生成这组ASM:
; At this point :
; r4 value is 0x20003201 (Address of radio_func)
7820 ldrb r0, [r4, #0] ; GCC treat correctly r4 as a pointer to 1 byte wide var, no problem here
f7ff ffcd bl 80098a8 <radio_get_mode> ; Call to radio_get_mode()
4d1e ldr r5, [pc, #120] ; r5 is loaded with 0x20003200 (Address of radio_mode)
6028 str r0, [r5, #0] ; Why GCC use 'str' and not 'strb' at this point ?这里的最后一行是问题:r0的值,radio_get_mode()的返回值,被存储到r5指出的地址中,作为一个32位值。因为radio_func是radio_mode之后的1字节,所以它的值被r0的第二个字节覆盖(因为枚举只有1字节宽,所以始终是0x00 )。
既然我的函数radio_get_mode被声明为返回一个单字节,为什么GCC不使用指令strb将这个单字节保存到r5指出的地址中?
我试过:
radio_get_mode()作为返回uint8_t:uint8_t radio_get_mode(enum eRadioFunction _radio_func);uint8_t:radio_mode = (uint8_t)radio_get_mode(radio_func);uint32_t r = radio_get_mode(radio_func);
radio_mode = (uint8_t) r;但这些解决方案都不起作用。
由于规模优化(-Os)是第一次需要的,以减少rom的使用(而不是ram -在我的项目的这个时候),我发现解决方法gcc选项-fno-short-enums将允许编译器使用4个字节的枚举,放弃任何重叠的内存在这种情况下。
但是,在我看来,这是一个隐藏真正问题的肮脏方法:
提前谢谢。
编辑:
-f-short-enums。radio_mode和radio_func声明为uint8_t (又称unsigned char):问题是相同的。H 250H 151用-Os编译时,Output.map如下:H 253F 254Common symbol size file
...
radio_mode 0x1 src/radio/radio.o
radio_func 0x1 src/radio/radio.o
...
...
...
Section address label
0x2000319c radio_state
0x20003200 radio_mode
0x20003201 radio_func
0x20003202 radio_protocol
...映射文件的输出清楚地表明,radio_mode和radio_func的宽度为1字节,并且位于以下地址。
在没有-f-short-enums)
-Os和-fno-short-enums编译时,-Os的所有枚举所做的事情相同(这就是为什么-Os意味着隐式H 270H 171)。我对问题的分析是,我很确定它是编译器错误。对我来说,这显然是记忆的重叠。我的问题更多地是为了避免这种情况而做的最好的事情--以“最佳实践”的方式。编辑2
这是我的错,我有重新测试人员将所有签名更改为uint8_t (又名unsigned char),并且运行良好。
@彼得·科德斯(Peter)似乎在这里发现了这个问题:当使用它时,-Os在一定程度上支持-fshort-enums,让GCC的一些部分将其视为1号尺寸,而其他部分则将其视为4号尺寸。
仅使用uint8_t的ASM代码是:
; Same position than before
7820 ldrb r0, [r4, #0]
f7ff ffcd bl 80098a8 <radio_get_mode>
4d1e ldr r5, [pc, #120]
7028 strb r0, [r5, #0] ; Yes ! GCC use 'strb' and not 'str' like before !澄清:
-Os和枚举时似乎存在编译器错误。不幸的是,overlap.-fno-short-enums与-Os的关系似乎是一个很好的解决办法,因为问题只涉及到枚举,而不是所有的1字节变量。再次感谢。
发布于 2020-06-18 09:16:17
ARM端口abi将none-aebi枚举定义为可变大小类型,linux定义为标准固定类型。
这就是你所观察到的行为的原因。这与优化无关。
在这个例子中,您可以看到它是如何工作的。https://godbolt.org/z/-mY_WY
https://stackoverflow.com/questions/62435341
复制相似问题