I have some misunderstanding about MCU GCC compilation behavior regarding function that return other things that 32bits value.
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)
My code is optimized for size (with option -Os
). In my understanding, this will allow the gcc to use implicit -fshort-enums
in order to pack enums.
I have two enum var, 1-byte wide:
enum eRadioMode radio_mode // (@ 0x20003200)
enum eRadioFunction radio_func // (@ 0x20003201)
And a function:
enum eRadioMode radio_get_mode(enum eRadioFunction _radio_func);
When i call this bunch of code:
radio_mode = radio_get_mode(radio_func);
It will produce this bunch of ASM at compile time:
; 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 ?
The last line here is the problem: The value of r0
, return value of radio_get_mode()
, is stored into address pointed by r5
, as a 32bit value. Since radio_func
is 1 byte after radio_mode
, its value is overwritten by the second byte of r0
(that is always 0x00 since enum is only 1 byte wide).
As my function radio_get_mode
is declared as returning 1 single byte, why GCC doesn't use instruction strb
in order to save this single byte into the address pointed by r5
?
I have tried:
radio_get_mode()
as returning 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;
But none of these solutions work.
Since the size optimization (-Os) is needed in first sight to reduce rom usage (and not ram - at this time of my project -) I found that the workaround gcc option -fno-short-enums
will let the compiler to use 4 bytes by enum, discarding by the way any overlapping memory in this case.
But, in my opinion, this is a dirty way to hide a real problem here:
Thanks in advance.
EDIT:
-f-short-enums
at any moment.radio_mode
and radio_func
as uint8_t
(aka unsigned char
): The problem is the same.-Os
, Output.map is as follow:
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
...
The output of the mapfile show clearly that radio_mode
and radio_func
is 1 byte wide and at following address.
-Os
, Output.map show clearly that enums become 4 byte wide (with address padded to 4).-Os
and -fno-short-enums
, do the same things that without -Os
for all enums (This is why I guess -Os
implies implicit -f-short-enums
)EDIT 2
It is my bad, I have re-tester changing all signature to uint8_t
(aka unsigned char
) and it work well.
@Peter Cordes seems to found the problem here: When using it, -Os
is partly enabling -fshort-enums
, getting some parts of GCC to treat it as size 1 and other parts to treat it as size 4.
ASM code using only uint8_t
is:
; 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 !
To clarify:
-Os
and enums. This is bad luck that two enum is at consecutive adresses that overlap.-fno-short-enums
in conjonction with -Os
appear to be a good workaround IMO, since the problem is concerning only enum, and not all 1 byte var at all.Thanks again.
ARM port abi defines none-aebi enums to be a variable sized type, linux-eabi to be standards fixed one.
That is the reason the behaviour you observe. It is not related to the optimisation.
In this example you can see how it works. https://godbolt.org/z/-mY_WY
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.