Search code examples
clinkeriar

How to declare variables and register their addresses to an array at link time


THE GOAL:
I want different .c files to be able to declare variables and register the address of said variables into an array located at the beginning of linker section __my_registry_section__.

user1.c:

#include "register.h"

REGISTER(struct thing, myThing1);
REGISTER(struct thing, myThing2);

user2.c:

#include "register.h"

REGISTER(struct thing, myThing3);

The idea is that after compilation the array located at the beginning of the block in __my_registry_section__ will contain entries:

(order does not matter)
[0] &myThing3
[1] &myThing1
[2] &myThing2

THE CURRENT METHOD:
I have a macro that first declares the variable and next adds the address of variable into the section by declaring a void* with an unused name that is directed by a pragma to be located in the next available space in the registry section where the order does not matter.

register.h:

#define REGISTER(TYPE, NAME)     TYPE _##NAME;   /* allocate data */     \
                                _Pragma("location=\"__my_registry_section__\"") void* whatever##NAME = &_##NAME  /* place address of data into array */

THE PROBLEM::
The method works, but only if you explicitly reference the void* whatever##NAME (e.g. printf("%x", whatevermyThing1)). However I don't want to have to reference these variables.

The variable void* whatever##NAME is never referenced (it's only there as an excuse to place the pointer into the section), so it never gets emitted into the object file. I tried using __attribute__((used)) but it appears to not be available in IAR C. I also tried adding _Pragma("required=whatever##NAME") in order to force the symbol to be used but the # character is supposedly illegal inside the pragma. But even if I hard-code one of the variable names like so _Pragma("required=whatevermyThing1"), the compiler complains with

Warning[Pe609]: this kind of pragma may not be used here

Is there a way to force the compiler to emit the symbol without using this pragma? Is there another completely different approach?

Note, there is an existing question (Declare a variable and add it to an array at compile time) that's pretty identical to mine, but the solution is actually just building the array at runtime, so not useful.


Solution

  • There is a simple solution to you problem. There is an object attribute __root that indicates to the linker that this object should be included in the output even if it is not referenced anywhere. If you add this attribute to the declaration of whatever##NAME it will be included in the linked binary. This slots easily into your current solution, you only need to update register.h as shown below.

    #define REGISTER(TYPE, NAME)   TYPE _##NAME;   /* allocate data */     \
         _Pragma("location=\"__my_registry_section__\"") __root void* whatever##NAME = &_##NAME  /* place address of data into array */