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?

 

23 REPLIES 23

I think it's fine to target GCC as your compiler of choice for most users. Also ARM states on that page

Note: This variable attribute is a GNU compiler extension that the ARM compiler support

So that's a strong endorsement. I'm not sure whether the gcc arm toolchain ST uses is a pure GNU project, or whether ARM supports it (by paying their engineers to contribute) or something like that. But I'm sure all IDEs

can be configured to use it. and if you're switching to a "better compiler" it must have at least a similar facility. Would you tell someone not to use *that* to stay compatible with GCC? that's not practical.

 

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

no, per the documentation I linked, the attribute applies to functions. It doesn't say it *does not* apply to data, It's neutral, and I did mention this in my post as a (sidenote).

 kier points out that I got it right, but I should have looked at another doc page (*** you google). sorry for that.

 

Update: wow, the forum auto-censors "bad words" like d-amn. Soon, they'll be taking away our puppy cages.

- 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

Oops I stand corrected. 

But note that "To support this behavior, variables that have not been placed in specific sections (e.g. by the section attribute, or the -fdata-sections option), will be placed in new, unique sections." - so the linker script should be compatible with these new sections, or they may end in a wrong place.

BarryWhit
Lead II

Sure, but the default compilation flags under Cube already specify -ffunction-sections and -fdata-sections, I don't think anything manual needs to be done. I've worked with and modified the linker scripts in the past (to reserve a section of flash for NV storage for example), but I don't remember seeing anything there that explicitly handles these sections. I wonder how it works on the nitty-gritty level.

 

Just FYI, these options are very common optimizations used in embedded context. I've also seen them elsewhere outside the STM32 ecosystem.

- 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

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.

BarryWhit
Lead II

Manually editing the linker script is "cheating".

 

Also, the gcc compiler has no idea what's in the linker script. So if it really is an attribute-less, static, global, unreferenced variable, and you're compiling with -O2 (or whatever), and the object file contains this variable, it really shouldn't be there. That would really be a bug.

- 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.
BarryWhit
Lead II

I've manually verified my analysis from a prior comment, when using x86 GCC 14.1.1 on linux.

The only caveat is that the `used` and `retain` attributes appear to be complementary - i.e. you have to specify both.

Summary:

- if you attach the `used` AND `retain` attributes to a static global variable then

- ... even if you compile with -O2

- ... and even if you compile with -fdata-sections (AND)

- ... you link with -Wl,--gc-section

The variable will survive the process, and make it to the final ELF file. No modification to the linker script are required.

 

.PHONY: 1
1: 1.c
	gcc -O2 -fdata-sections -c 1.c -o 1.o
	gcc -Wl,--gc-section 1.o -o 1 
	-readelf -s 1.o | grep -i foo
	-readelf -s 1 | grep -i foo
#include <stdio.h>
#include <stddef.h>

#define KEEPER __attribute__((used)) __attribute__((retain))
static int foo KEEPER = 0;
int main(int argc, char const *argv[]) {
    printf("hello\n");
    return 0;
}

 

Output:

 

gcc -O2 -fdata-sections -c 1.c -o 1.o
gcc -Wl,--gc-section 1.o -o 1
readelf -s 1.o | grep -i foo
     4: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    7 foo
readelf -s 1 | grep -i foo
     4: 000000000040400c     4 OBJECT  LOCAL  DEFAULT   24 foo

 

@Kier , is this a solution or not?

 

- 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.
zack411
Associate

Thanks buddy!!!

Thanks again Barry for all the effort you have expended, it's appreciated.

Unfortunately it's a non starter because 'retain' is not supported in the compiler that comes with STM32CubeIDE.

Kier_0-1719992277543.png

Presumably this is because the conditions mentioned here are not met.

Kier_1-1719992563026.png

I've raised a ticket with ST. I'm sure they will come back to explain why it doesn't work.

The binutils version for my old(er) CubeIDE is 2.38.20220708, so that's not the issue.

It must be the ABI requirement that's not met.

 

I'm sure they will come back to explain why it doesn't work.

 

The 'used` attribute is working exactly as intended. If you remove the  "--gc-sections" linker options, the variable will appear in the output.

The default linker options for Cube projects (helpfully) include "--gc-sections". Which means you've asked (*) the linker to prune the variable (to the linker, this is just an unused section). This also, is exactly as intended.

I suggested `retain` as a workaround since you could have used to achieve your goal. Unfortunate that it isn't supported as you rightfully pointed out.

 

You could certainly ask ST OLS for advice on how to achieve your goal. I can suggest one as well:

- remove "-fdata-sections" from the compilation flags. Be aware that this may result in a larger final binary (**).

 

Overall, we've definitely answered your original question (as stated).

 

(*)

GC2.jpg

(**)

GC3.jpg

- 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

ST support mentioned that KEEP is needed in the linker script but have not acknowledged that this works without the used attribute. On the one hand there is a solution but on the other, the assertion in the title still holds true. 'used' attribute Appears Ineffective.

It looks like its only benefit is to document variables in the source that one intends to bypass unused section removal. In addition, if the same source (with 'used' attributes) was ported to a toolchain that did support 'used' (e.g. TI arm clang) it would not need further linker instructions. So for these reasons it is probably better to keep the 'used' attribute even though it doesn't do anything useful in the STM scenario.