首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >STM32单片机GCC编译行为

STM32单片机GCC编译行为
EN

Stack Overflow用户
提问于 2020-06-17 17:51:18
回答 1查看 436关注 0票数 0

对于GCC单片机的编译行为,我对32位值的其他功能有一些误解。

代码语言:javascript
复制
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字节宽:

代码语言:javascript
复制
enum eRadioMode         radio_mode // (@ 0x20003200)
enum eRadioFunction     radio_func // (@ 0x20003201)

和一项职能:

代码语言:javascript
复制
enum eRadioMode radio_get_mode(enum eRadioFunction _radio_func);

当我把这堆代码叫做:

代码语言:javascript
复制
radio_mode = radio_get_mode(radio_func);

它将在编译时生成这组ASM:

代码语言:javascript
复制
; 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_funcradio_mode之后的1字节,所以它的值被r0的第二个字节覆盖(因为枚举只有1字节宽,所以始终是0x00 )。

既然我的函数radio_get_mode被声明为返回一个单字节,为什么GCC不使用指令strb将这个单字节保存到r5指出的地址中?

我试过:

  • radio_get_mode()作为返回uint8_tuint8_t radio_get_mode(enum eRadioFunction _radio_func);
  • Forcing强制转换为uint8_tradio_mode = (uint8_t)radio_get_mode(radio_func);
  • Passing由第三个变量(但GCC取消在编译时的无用动作-不那么愚蠢) :

代码语言:javascript
复制
uint32_t r = radio_get_mode(radio_func);
radio_mode = (uint8_t) r;

但这些解决方案都不起作用。

由于规模优化(-Os)是第一次需要的,以减少rom的使用(而不是ram -在我的项目的这个时候),我发现解决方法gcc选项-fno-short-enums将允许编译器使用4个字节的枚举,放弃任何重叠的内存在这种情况下。

但是,在我看来,这是一个隐藏真正问题的肮脏方法:

  • 是GCC不能正确处理32位以外的其他返回大小吗?
  • 有正确的方法吗?

提前谢谢。

编辑:

  • I在任何时候都没有使用-f-short-enums
  • 我确信这些枚举没有大于0xFF
  • 的值,我尝试将radio_moderadio_func声明为uint8_t (又称unsigned char):问题是相同的。H 250H 151-Os编译时,Output.map如下:H 253F 254

代码语言:javascript
复制
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
...

映射文件的输出清楚地表明,radio_moderadio_func的宽度为1字节,并且位于以下地址。

在没有-f-short-enums)

  • I的情况下编译
  • 时,Output.map清楚地显示枚举的宽度为4字节(地址填充为4)。使用-Os-fno-short-enums编译时,
  • 所做的事情与没有-Os的所有枚举所做的事情相同(这就是为什么-Os意味着隐式
  • 将尝试提供最小的可重复示例H 270H 171)。我对问题的分析是,我很确定它是编译器错误。对我来说,这显然是记忆的重叠。我的问题更多地是为了避免这种情况而做的最好的事情--以“最佳实践”的方式。

编辑2

这是我的错,我有重新测试人员将所有签名更改为uint8_t (又名unsigned char),并且运行良好。

@彼得·科德斯(Peter)似乎在这里发现了这个问题:当使用它时,-Os在一定程度上支持-fshort-enums,让GCC的一些部分将其视为1号尺寸,而其他部分则将其视为4号尺寸。

仅使用uint8_t的ASM代码是:

代码语言:javascript
复制
    ; 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.
  • Using -fno-short-enums-Os的关系似乎是一个很好的解决办法,因为问题只涉及到枚举,而不是所有的1字节变量。

再次感谢。

EN

回答 1

Stack Overflow用户

发布于 2020-06-18 09:16:17

ARM端口abi将none-aebi枚举定义为可变大小类型,linux定义为标准固定类型。

这就是你所观察到的行为的原因。这与优化无关。

在这个例子中,您可以看到它是如何工作的。https://godbolt.org/z/-mY_WY

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62435341

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档