I have an ARM project, where I would like to keep certain unused variables and their data, until the time they are used.
I have seen prevent gcc from removing an unused variable :
__attribute__((used))
did not work for me with a global variable (the documentation does imply it only works on functions) (arm-none-eabi gcc 7), but putting the symbol in a different section via__attribute__((section(".data")))
did work. This is presumably because the linker's is only able to strip symbols when they are given their own section via-fdata-sections
. I do not like it, but it worked.
So, I tried this approach, but the variables were not kept - and I think this is because something in that project enables -Wl,--gc-sections
during linking. Here is a minimal example showing what I've tried to do (basically the main file only refers to the header where the variables to be "kept" are declared as extern - and other than that, main program has does not use these variables; and then those same variables are defined in a separate .c file):
test.c
#include <stdio.h>#include "test_opt.h"const char greeting[] = "Hello World - am used";int main(void) { printf("%s!\n", greeting); return 0;}
test_opt.h
#include <stdint.h>extern const char mystring[];struct MyStruct { uint16_t param_one; uint8_t param_two; unsigned char param_three[32];};typedef struct MyStruct MyStruct_t;extern const MyStruct_t mystruct;
mystruct.c
#include "test_opt.h"const char __attribute__((section(".MYSTRING"))) mystring[] = "Me, mystring, I am not being used";const MyStruct_t __attribute__((section(".MYSTRUCT"))) mystruct = { .param_one = 65535, .param_two = 42, .param_three = "myStructer here",};
Test with usual MINGW64 gcc
Let's first try without -Wl,--gc-sections
:
$ gcc -Wall -g mystruct.c test_opt.c -o test_opt.exe$ strings ./test_opt.exe | grep -i 'mystring\|mystruct'Me, mystring, I am not being used*myStructer heremystringMyStructMyStruct_tmystructmystruct.cmystruct.cmystruct.cmystruct.cmystringmystruct.MYSTRING.MYSTRUCT.MYSTRING.MYSTRUCT
Clearly, variables and content are visible here.
Now let's try -Wl,--gc-sections
:
$ gcc -Wall -g -Wl,--gc-sections mystruct.c test_opt.c -o test_opt.exe$ strings ./test_opt.exe | grep -i 'mystring\|mystruct'mystringMyStructMyStruct_tmystructmystruct.cmystruct.cmystruct.cmystruct.cmystringmystruct
Apparently, here we still have some symbol debugging info left - but there are no sections, nor data being reported.
Test with ARM gcc
Let's re-do same experiment with ARM gcc - first without -Wl,--gc-sections
:
$ arm-none-eabi-gcc -Wall -g test_opt.c mystruct.c -o test_opt.elf -lc -lnosys$ arm-none-eabi-strings ./test_opt.elf | grep -i 'mystring\|mystruct'Me, mystring, I am not being used*myStructer heremystruct.cMyStruct_tMyStructmystructmystruct.cmystringmystruct.cmystringmystruct.MYSTRING.MYSTRUCT
Same as before, variables, content and section names are visible.
Now let's try with -Wl,--gc-sections
:
$ arm-none-eabi-gcc -Wall -g -Wl,--gc-sections test_opt.c mystruct.c -o test_opt.elf -lc -lnosys$ arm-none-eabi-strings ./test_opt.elf | grep -i 'mystring\|mystruct'
Note that, unlike the previous case, here there is neither any data content left, nor any debugging info/symbol names!
So, my question is: assuming that -Wl,--gc-sections
is enabled in the project, and I otherwise do not want to remove it (because I like the functionality otherwise), can I somehow specify in code for some special variables, "keep these variables even if the are unused/unreferenced", in such a way that they are kept even with -Wl,--gc-sections
enabled?
Note that adding keep
to attributes, say:
const char __attribute__((keep,section(".MYSTRING"))) mystring[] = "Me, mystring, I am not being used";
... and compiling with (or without) -Wl,--gc-sections
typically results with compiler warning:
mystruct.c:3:1: warning: 'keep' attribute directive ignored [-Wattributes] 3 | const char __attribute__((keep,section(".MYSTRING"))) mystring[] = "Me, mystring, I am not being used"; | ^~~~~
... I guess, because the variables are already declared const
if I read that arrow correctly (or maybe because a section is already assumed to be "kept")? So attribute keep
is definitely not the answer here ...