I'm writing a bare metal application for an ARM device (no OS). I need 32-bit enums, so I compiled the application with the -fno-short-enums
compiler flag. Without this flag, I get variable enums (and enforcing the size by adding an additional 0xFFFFFFFF
value to each enum is not an option).
Now I get the following linker warning for every object:
c:/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/6.2.1/../../../../arm-none-eabi/bin/ld.exe: warning: ./src/test.o uses 32-bit enums yet the output is to use variable-size enums; use of enum values across objects may fail
It's just a warning, no error. But what does it mean exactly? How can I specify the "output"?
I tried to recompile the newlib with the above flag to ensure that all objects use the same enum size, but I'm still getting the warning. Is there something I missed?
I have a partial answer as I had the same question. The problem is a warning message from the linker that will appear with the use of -fno-short-enums. The message indicates that the target object is not compatible. So I spent a world of time looking for now to change the target to be compatible.
But that wasn't the problem. The gcc compiler will build 32-bit enums by default!! So this option is no necessary unless you DONT want 32-bit enums. However, if you do specify the -fno-short-enums you will receive the warning message. Unfortunately I don't know why.
So the bottom line is that the no-short-enums flag is not necessary to achieve 32-bit enums. If you do specify it then you will receive the warning message.
After a while I got it working. I rebuilt the whole toolchain including the compiler with this flag. Here is the way I did:
Get the toolchain source from https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads
Add 3 lines to some sections of the buildscript build-toolchain.sh
:
saveenv saveenvvar CFLAGS_FOR_TARGET '-fno-short-enums' [...build commands...] restoreenv
Modified sections:
Task [III-1] /$HOST_NATIVE/gcc-first/
Task [III-2] /$HOST_NATIVE/newlib/
Task [III-4] /$HOST_NATIVE/gcc-final/
Task [IV-3] /$HOST_MINGW/gcc-final/
I Skipped building newlib-nano
and gcc-size-libstdcxx
.
Run the modified Scripts build-prerequisites.sh
and build-toolchain.sh
to build everything.
After that, the compiler is using the large-enum-mode and the linker is fine with my objects. But now, I get the opposit warning for some objects of the newlib ( lib_a-mbtowc_r.o
, lib_a-svfiprintf.o
, lib_a-svfprintf.o
, lib_a-vfprintf.o
and lib_a-vfiprintf.o
):
c:/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/6.2.1/../../../../arm-none-eabi/bin/ld.exe: warning: c:/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/6.2.1/../../../../arm-none-eabi/lib\libc.a(lib_a-mbtowc_r.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
I looked into the makefiles of these object and they are explicitly set to variable-size-enums, sadly. The only "solution" for this, was to add a linker flag to mute this warning:
-Xlinker -no-enum-size-warning
That's it.
I ran into the same problem since I have a lot of enums in data structures that map to hardware. In my case, my fix is to do the following:
struct x {
union {
enum my_enum eval;
uint32_t :32;
};
uint32_t some_val;
...
}
This works and is transparent outside of the data structure, though it means that every time an enum is used in a data structure this union wrapper is required. I suppose a macro might be possible as well. I agree it's a pain. Every other 32-bit and 64-bit environment I've worked with treats enums as 32-bits and don't get me started with the decision to make a uint32_t an unsigned long in the ARM embedded ABI (every other one I've worked with it's an unsigned int, making portability with 64-bit ABIs easy).
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.