Issue preventing GCC from optimizing out global variable

Asked by Radu

Hi,

I am using ARM-GCC v4.9 (released 2015-06-23) for a STM32F105RC processor.
I've searched stackoverflow.com and I've found this in order to try to convince gcc not to optimize out a global variable, as you may see below:

static const char AppVersion[] __attribute__((used)) = "v3.05/10.oct.2015";

Yet, to my real surprise, the compiler optimized away the AppVersion variable!
BTW: I am using the optimize level -O0 (default).
I also tried using volatile keyword (as suggested on other thread), but it didn't work either :(
I already tried (void)AppVersion; but it doesn't work...
Smart compiler!? Too smart I suppose...

In the meantime, I use a printf(AppVersion); some place in my code, just to be able to keep the version... But this is a boorish solution :(
So, the question is: Is there any other trick that does the job, i.e. keep the version from being optimized away by GCC?... Some #pragma or an attribute...or linker option(s) ?

I also tried like this (i.e. without static):

const char AppVersion[] __attribute__((used)) = "v3.05/10.oct.2015";

... and it didn't work either :(

Many thanks in advance for your help!
Stanley G.

Question information

Language:
English Edit question
Status:
Solved
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Solved by:
Andre Vieira
Solved:
Last query:
Last reply:
Revision history for this message
Radu (stanley-groenhen) said :
#1

Same issue when using ARM-GCC v4.9 (released 2015-09-25).

Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#2

Hi Radu,

I cannot reproduce your issue with out 2015Q4 toolchain:

% cat main.c
static const char AppVersion[] __attribute__ ((used)) = "v3.05/10.oct.2015";

int
main (void)
{
  return 0;
}

% arm-none-eabi-gcc -o main.axf main.c -specs=rdimon.specs
% strings main.axf | grep oct
v3.05/10.oct.2015

Can you give us some more detailed instructions on how to reproduce this issue? In the meantime you can try removing the const qualifier.

Best regards.

Revision history for this message
Radu (stanley-groenhen) said :
#3

Hi Thomas,

First, thanks for taking the time to answer.

Well, I didn't have the chance to install the new version 5.0 of the toolchain (or is it 5.2? :-)

All the test were done using the version 4.9 (released 2015-09-25).
Even if the string was definitely there in the object file main.o (or main.obj - can't remember exactly),
the string was removed after that by the linker, so I clearly wasn't able to find it in the executable *.HEX file!

So, briefly, the point is: yes, the string is there in the object file(s), yet it is wiped out by the linker...
Unfortunately, now I am not able to test it using the newer version v5.x of the toolchain.

Kind regards,
Radu.

Revision history for this message
Andre Vieira (andre-simoesdiasvieira) said :
#4

Hi Radu,

I can not reproduce it with the 4.9 toolchain either.

$arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.9.3 20150529 (release) [ARM/embedded-4_9-branch revision 227977]
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ cat t.c
static const char AppVersion[] __attribute__ ((used)) = "v3.05/10.oct.2015";

int
main (void)
{
    return 0;
}

$arm-none-eabi-gcc t.c --specs=rdimon.specs
$arm-none-eabi-strings a.out
v3.05/10.oct.2015

Can you provide us with the full compilation command line?

Cheers,
Andre

Revision history for this message
Radu (stanley-groenhen) said :
#5

Hi Andre,

One question: "a.out" is the output of the compiler as an <object> file?
Or is it the output of the LINKER, i.e. something like a BIN or HEX file ?

I am not a guru of compilers or linkers, as a matter of fact I am using an IDE that makes all this things transparently (compile, build, etc)...
So, to answer your question: There is no "command line", the IDE named CoIDE (www.coocox.org) does all the stuff.
Yet, I am 99.99% sure that my problem is not caused by the compiler, but by the linker (please, see my previous message).
"...briefly, the point is: yes, the string is there in the object file(s), yet it is wiped out by the linker..."

OTOH, I will try tomorrow to see if there is a way to expose what exactly is CoIDE feeding the compiler and linker with.
But, again, I am pretty sure it's the linker who has to be convinced somehow not to wipe away the AppVersion string...

Best regards,
Radu.

Revision history for this message
Andre Vieira (andre-simoesdiasvieira) said :
#6

Hi Radu,

'a.out' is the binary/executable and thus the result of the linker.

I had a look at CooCoox and it passes --gc-sections by default. Right click on the project, in the project navigation panel and choose Configuration. Then go to the tab "Link" and uncheck "Discard unused sections".

This should do the trick.

Cheers,
Andre

Revision history for this message
Radu (stanley-groenhen) said :
#7

Hi Andre,

Unchecking that option "Discard unused sections" brings back the AppVersion string into the binary/executable file, but unfortunately with a huge penalty: the size of the binary file is now about 31% bigger than before... :(

I was thinking maybe(?) there is another way to solve the issue, something that allows me to keep only that particular string, not ALL unused strings/sections.

For example I saw some other compilers/linkers (for Atmel if I recall well) offer something like this to be used in the source code
(now I realize there's only one way to solve the problem... i.e. at source-code level) :
     #pragma keep+
      < code >
     #pragma keep-

Maybe you have a clue if this can be done also for ARM GCC by any chance...?

Many thanks in advance!
Obrigado,
Radu.

Revision history for this message
Best Andre Vieira (andre-simoesdiasvieira) said :
#8

Hehe,

No problem ;)

 Unfortunately I am not aware of a pragma to do this. There is however another solution. Change AppVersion to:

static char * AppVersion = "v3.05/10.oct.2015";

and add:

__asm__ ("" : : "" (AppVersion));

to your main function.

You see I dropped the 'used' attribute, according to the documentation this is a function attribute.

Other solutions: http://stackoverflow.com/questions/16349557/does-gcc-have-any-options-to-add-version-info-in-elf-binary-file

Though I found this one to be the easiest. This basically won't let the compiler and linker remove AppVersion since we told it the that piece of inline assembly uses it, even though we don't actually insert any inline assembly.

Hopefully that will be satisfactory to you.

Revision history for this message
Radu (stanley-groenhen) said :
#9

Hi Andre,

Yes, indeed ...
__asm__ ("" : : "" (AppVersion));
... solved the problem :)

I want to express my gratitude for your valuable help!

If you are a member of stackoverflow.com, please spend few seconds to copy your above answer and paste it as an answer here:
http://stackoverflow.com/questions/33351690/issue-preventing-gcc-from-optimizing-out-global-variable

Other people on stackoverflow showed real interest in this matter, so they could benefit also from your idea.
Of course, I would be very happy to vote it :-)

OTOH, if you don't have an account on stackoverflow, I will ask for your permission to post your answer there, mentioning of course you name as the author and adding a link to this site/forum.

Com os melhores cumprimentos,
Radu.

Revision history for this message
Radu (stanley-groenhen) said :
#10

Thanks Andre Vieira, that solved my question.