cancel
Showing results for 
Search instead for 
Did you mean: 

'used' attribute Appears Ineffective

Kier
Associate III

Hello,

According to the manual , "This attribute, attached to a variable with static storage, means that the variable must be emitted even if it appears that the variable is not referenced."

In the following code, unreferenced_variable is always discarded:

static uint8_t unreferenced_variable __attribute__((used));

There's no warning from the compiler.

  1. Is 'used' supported in principle please?
  2. Is there a problem with the syntax?

 

1 ACCEPTED SOLUTION

Accepted Solutions
Kier
Associate III

OK, I stumbled on a workaround while browsing the linker script. I added line 9:

 

  .bss :
  {
    /* This is used by the startup in order to initialize the .bss section */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)
    KEEP (*(.bss.unreferenced_variable*))
    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM_D1

 

And there it is:

Kier_2-1719993243147.png

Bafflingly, this works even if 'used' attribute is not applied. I would have thought it would be the minimum necessary to emit the variable in the .o file and that the KEEP line would be the last piece of the puzzle, but no.

So 'used' is still, frankly, pointless.

View solution in original post

23 REPLIES 23
AScha.3
Chief III

Hi,

see here:

https://stackoverflow.com/questions/31637626/whats-the-usecase-of-gccs-used-attribute

>

This attribute, attached to a function, means that code must be emitted for the function even if it appears that the function is not referenced. This is useful, for example, when the function is referenced only in inline assembly.

<

+

If you declare a global variable or function that is unused, gcc will optimized it out (with warning), but if you declared the global variable or the function with '__attribute__((used))', gcc will include it in object file (and linked executable).

or from ARM , for GCC :

https://developer.arm.com/documentation/dui0472/m/Compiler-specific-Features/--attribute----used---variable-attribute

> static int keep_this __attribute__((used)) = 2; // retained in object file

 

If you feel a post has answered your question, please click "Accept as Solution".
BarryWhit
Lead II

By default optimized builds are compiled with `-ffunction-sections -fdata-sections` options and linked with the `-gc-sections` option. So, in all likelihood, the unused variable is preserved by the compiler (not optimized away) as AScha.3 explained (i.e. it's present in the .o file), but is then pruned away at link time (i.e. it's eliminated from the final .elf file).

GC.jpg

 

This is a very good thing to have on by default for optimized builds since it significantly reduces binary size, and space is usually a scarce resource in embedded systems.

- If someone's post helped resolve your issue, please thank them by clicking "Accept as Solution".
- Please post an update with details once you've solved your issue. Your experience may help others.
Kier
Associate III

Many thanks for your replies.

It's true that my variable is being pruned away by the linker but why? That's my question. All the sources cited suggest this should not happen.

In @AScha.3's reply, it says: "will include it in object file (and linked executable)"

Also the ARM doc URL cited says: 

"Data marked with __attribute__((used)) is tagged in the object file to avoid removal by linker unused section removal."

In both cases the effect in bold above is not being realised. The point of this attribute is to ultimately override unused section removal in the linker. If it's only partially effective in the toolchain it might as well not be supported at all.

Note that exactly the same source code in a different compiler toolchain (TI Arm Clang) has the desired effect even when unused section elimination is switched on.

I tried to use 'retain' but this is actively ignored (not supported?) by the compiler.

I conclude so far that I'm using it correctly and the expectation that it shall survive linker pruning is legitimate. The problem remains, however, why it's not happening in this case.

BarryWhit
Lead II

"Data marked with __attribute__((used)) is tagged in the object file to avoid removal by linker unused section removal."

I was not aware of this claim. Find more information about this "tag", and you should able to make progress figuring out why the linker is pruning the variable. You could probably use `objdump` or `readelf` to look at the object file and identify the nature of this "mark", if there is no documentation. Than we need to find out why ld isn't considering it. Perhaps the default linker flags used by ST neglect to add a special exclusion pattern based on this tag. I'm not familiar with that functionality in `ld`, but apparently some kind of linker option for doing this does exist. Find it, report it to ST, wait 6-18 months, and presto you may have solved this problem for every ST customer that walks in your footsteps. Well done!

- If someone's post helped resolve your issue, please thank them by clicking "Accept as Solution".
- Please post an update with details once you've solved your issue. Your experience may help others.
Kier
Associate III

Thanks for the encouragement Barry.

I'll do a bit more digging but I'll also raise a support ticket now that I know the topic has been sanity checked.

BarryWhit
Lead II

Sigh. So there seems to be some disagreement about the semantics of used. Some say it means it should be emitted to the object file (but may be prune by linker gc options), and some some say it should remain the the final elf.

Please see this SO answer, which suggest what you want is actually the "retain" attribute.

The gcc documentation suggest this is correct (at least when the attribute is applied to functions):

 

retain

For ELF targets that support the GNU or FreeBSD OSABIs, this attribute will save the
 function from linker garbage collection. To support this behavior, functions that have
 not been placed in specific sections (e.g. by the section attribute, 
or the -ffunction-sections option), will be placed in new, unique sections.

This additional functionality requires Binutils version 2.36 or later.

 

The way I explain my way out of this bowl of spaghetti is:

1. An unreferenced static (i.e. file-scoped) global variable will be eliminated by the compiler if (Certain) optimizations are turned on.

2. ...Unless the the variable is annotated with the "used" attribute, In which case it will be included in both the object and the final elf file.

3. ...Unless you specifically ask the linker to gc unused sections  (and used -fdata-section during compilation),

 in which case the variable will not be included by the linker in the final output elf file.

4. ...Unless you annotate the variable with the "retain" attribute, in which case the linker GC will skip over the variable, and it will be emitted in the final elf file.

- If someone's post helped resolve your issue, please thank them by clicking "Accept as Solution".
- Please post an update with details once you've solved your issue. Your experience may help others.
Pavel A.
Evangelist III

Per the gcc documentation attribute retain applies to functions, not to data.

CubeIDE uses GCC compilers and linkers. Other compilers (TI, Keil v.5 and so on) may have the __attribute__ keyword like GCC and clang, but the attributes and their effect can differ. Avoid non-portable compiler extensions, be safe.

 

It depends which page you're reading. 'retain' is described for variables too.

Common Variable Attributes (Using the GNU Compiler Collection (GCC))

Thanks Barry.

I'm still struggling to understand why emitting the symbol in the object file but then discarding in the linker has any use.

It's true that 'retain' may be the answer but it's not supported.

I'm happy to use any attribute, keyword or pragma that succinctly achieves the desired effect, that of making an exception for 'discard unused sections' link option.

A typical use case could be that a part number string is compiled in a boot loader and the string is located at a fixed address. There are no references to that part number in the BL program, only the application program is required to read it by pointer. How can I prevent the part number from being discarded when I compile the BL? It seems the only way is to write some dummy code in the BL to to reference the BL part number.