[英]STM32 MCU GCC Compilation behavior
我对 MCU GCC 关于 function 的编译行为有一些误解,它返回其他 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)
还有一个 function:
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()
的返回值,作为 32 位值存储到r5
指向的地址中。 由于radio_func
在radio_mode
之后是 1 个字节,它的值被r0
的第二个字节覆盖(因为枚举只有 1 个字节宽,所以它总是 0x00)。
由于我的 function radio_get_mode
被声明为返回 1 个单字节,为什么 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枚举字节,在这种情况下丢弃任何重叠的 memory。
但是,在我看来,这是一种隐藏真正问题的肮脏方式:
提前致谢。
编辑:
-f-short-enums
。radio_mode
和radio_func
声明为uint8_t
(又名unsigned char
):问题是一样的。-Os
时, Output.map 如下:
Common 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
...
mapfile 的 output 清楚地显示radio_mode
和radio_func
为 1 字节宽,并位于以下地址。
-Os
的情况下编译时, Output.map 清楚地显示枚举变为 4 字节宽(地址填充为 4)。-Os
和-fno-short-enums
编译时,对所有枚举执行与没有-Os
相同的操作(这就是我猜-Os
暗示隐含-f-short-enums
原因)编辑 2
这是我的错,我重新测试员将所有签名更改为uint8_t
(又名unsigned char
)并且效果很好。
@Peter Cordes 似乎在这里发现了问题:使用它时, -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
和枚举时似乎存在编译器错误。 两个枚举位于重叠的连续地址上,这很不幸。-fno-short-enums
与-Os
结合使用似乎是 IMO 的一个很好的解决方法,因为问题仅涉及枚举,而不是所有 1 字节 var。再次感谢。
ARM 端口 abi 将 none-aebi 枚举定义为可变大小类型,将 linux-eabi 定义为标准固定类型。
这就是你观察到的行为的原因。 它与优化无关。
在此示例中,您可以看到它是如何工作的。 https://godbolt.org/z/-mY_WY
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.