7

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?

[EDIT]:
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 :(

סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68

3 Answers3

6

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: 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 that this piece of inline assembly uses it, even though we don't actually insert any inline assembly.

Hopefully that will be satisfactory to you.

Author: Andre Simoes Dias Vieira
Original link: https://answers.launchpad.net/gcc-arm-embedded/+question/280104

Community
  • 1
  • 1
סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68
5

Given the presence of "static", all your declaration does is ask the compiler to include the bytes representing characters of the string "v3.05/10.oct.2015" in some order at some arbitrary location within the file, but not bother to tell anyone where it put them. Given that the compiler could legitimately write that sequence of bytes somewhere in the code image file whether or not it appeared anywhere in the code such a declaration really isn't very useful. To be sure, it would be unlikely that such a sequence would appear in the code entirely by chance, and so scanning the binary image for it might be a somewhat reliable way to determine that it appeared in the code, but in general it's much better to have some means of affirmatively determining where the string may be found.

If the string isn't declared static, then the compiler is required to tell the linker where it is. Since the linker generally outputs the names and addresses of all symbols in a variety of places including symbol tables, debug-information files, etc. which may be used in a variety of ways that the linker knows nothing about, it may be able to tell that a symbol isn't used within the code, but can generally have no clue about whether some other utility may be expecting to find it in the symbol table and make use of it. A directive saying the symbol is "used" will tell the linker that even though it doesn't know of anything that's interested in that symbol, something out in the larger universe the linker knows nothing about is interested in it.

It's typical for each compilation unit to give a blob of information to the linker and say "Here's some stuff; I need a symbol for the start of it, but I can compute all the addresses of all the internals from that". The linker has no way of knowing which parts of such a blob are actually used, so it has no choice but to accept the whole thing verbatim. If the compiler were to include unused static declarations in its blob, they'd make it through to the output file. On the other hand, the compiler knows that if it doesn't export a symbol for something within that blob, nobody else downstream would be able to find it whether or not the object was included; thus, there would typically be little benefit to being able to include such a blob and compiler writers generally have to reason to provide a feature to force such inclusion.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • Yes, it really makes sense... I am not 100% sure, but I think I tried (few days ago) without using `static` and it didn't work... But ok, I don't wanna be pessimistic, I will try again tomorrow, now paying much more attention on the code, etc. – סטנלי גרונן Oct 26 '15 at 17:57
  • @groenhen: I'm not terribly familiar with the gcc toolchain, but what generally needs to happen is for something to tell the linker that something somewhere is interested in the symbol. This may often be accomplished either by using some kind of directive in the source code or by passing a command-line option to the linker. – supercat Oct 26 '15 at 18:05
  • To be honest, I would prefer a pragma/attribute _in the source code_, rather than messing with command line linker options :) – סטנלי גרונן Oct 26 '15 at 18:09
  • @groenhen: Which approach is better may depend upon what you're planning on doing with the symbol. If it's used by something in the build script, having it be part of the command-line options passed to the compiler by that build script may be sensible. In any case, I'd suggest that you look in both the compiler documentation and linker documentation, since both need to coordinate their efforts. – supercat Oct 26 '15 at 18:14
  • It would be useful to know where it is getting stripped out; i.e. is it a compiler problem or a linker problem? If you run with "compile-only" (-c) does the symbol exist in the resulting object? (it will need to be non-static - static things which are not used are at the mercy of the compiler even in -O0). – solidpixel Oct 27 '15 at 00:14
  • Well, I tested it without `static` and as I expected... **it didn't work**. Just to answer Isogen's question: It seems to be a linker _problem_, as the string is there in the object file. BTW: it didn't work even if I put extern AppVersion (yet didn't use it) in another source file. Smart linker! – סטנלי גרונן Oct 27 '15 at 08:01
  • @groenhen: Have you looked in the linker documentation yet? The compiler clearly has to include the data in the object file, since it has no idea if anyone else will need it; I wouldn't have been terribly surprised if __attribute__((used)) had conveyed the necessary information to the linker, but it appears likely that it doesn't. There may be some other attribute or pragma you can use, or you may have to configure things on the linker side. Doing the latter would likely give you some more flexibility with regard to where you want the string to be placed, which could be helpful. – supercat Oct 28 '15 at 15:47
  • @supercat: Not yet... I had to switch to some other project that has the deadline tomorrow and one of my colleagues is in hospital now so I had to take part of his tasks in order to help the team finalize the ongoing project... I will try to find and download the liker doc from launchpad.net (or something) next week, and I will also ask the guys that maintain the ARM GCC project what solution would they recommend in order to solve my problem. But, I definitely think your statements are correct, there MUST be some other pragma or attribute...or linker option(s)! Kind regards! – סטנלי גרונן Oct 29 '15 at 16:47
0

It seems that using a custom section also works.

Instead of

__attribute__((used))

try with

__attribute__((section(".your.section.name.here")))

The linker won't touch it, nor will the strip command.

Fabio A.
  • 2,517
  • 26
  • 35