[英]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.