[RTEMS Project] #2408: Linker set based initialization
RTEMS trac
trac at rtems.org
Wed Sep 2 12:52:05 UTC 2015
#2408: Linker set based initialization
-----------------------------+------------------
Reporter: sebastian.huber | Owner:
Type: enhancement | Status: new
Priority: normal | Milestone: 4.12
Component: General | Version: 4.10
Severity: normal | Keywords:
-----------------------------+------------------
Linker sets are used for example in Linux, FreeBSD (they are used in the
RTEMS port of the FreeBSD network stack, e.g. libbsd), eCos and for global
C++ constructors. They provide a space efficient and flexible means to
initialize modules. A linker set consists of
* dedicated input sections for the linker (e.g. `.ctors` and `.ctors.*` in
the case of global constructors),
* a begin marker (e.g. provided by `crtbegin.o`, and
* an end marker (e.g. provided by `ctrend.o`).
A module may place a certain data item into the dedicated input section.
The linker will collect all such data items in this section and creates a
begin and end marker. The initialization code can then use the begin and
end markers to find all the collected data items (e.g. function pointers).
Lets look how this works using a simple example. For this we need three
files `myset.h`,
{{{
#!c
#ifndef MYSET_H
#define MYSET_H
/* The linker set items */
typedef struct {
void (*func)(void);
} item;
/*
* Macro to create a linker set item. The first parameter is
* the designator of the item. It must be unique within the
* module scope. The second parameter is the desired function.
*/
#define MYSET_ITEM(i, f) \
__attribute__((used)) \
__attribute__((section(".rtemsroset.myset.content"))) \
static item i = { f }
#endif /* MYSET_H */
}}}
`module.c`
{{{
#!c
#include "myset.h"
#include <stdio.h>
/*
* Some global function that needs a module specific
* intialization done by f().
*/
void
g(void)
{
printf("g()\n");
}
/* The module constructor */
static void
f(void)
{
printf("f()\n");
}
/*
* This registers the module constructor f()
* in the linker set "myset".
*/
MYSET_ITEM(i, &f);
}}}
and `init.c`.
{{{
#!c
#include "myset.h"
#include <stddef.h>
/* Should be in a proper header file */
void g(void);
/* Define the start marker */
__attribute__((used))
__attribute__((section(".rtemsroset.myset.begin")))
static volatile const item begin[0];
/* Define the end marker */
__attribute__((used))
__attribute__((section(".rtemsroset.myset.end")))
static volatile const item end[0];
int main(void)
{
size_t n = &end[0] - &begin[0];
size_t i;
/* Call all functions of the linker set */
for (i = 0; i < n; ++i) {
(*begin[i].func)();
}
/*
* This will pull in the module.c and register its item in the
* linker set "myset". So g() can rely on f() being called first.
*/
g();
return (0);
}
}}}
In the linker command file of the GNU linker we need the following
statement.
{{{
.rtemsroset : {
KEEP (*(SORT(.rtemsroset.*)))
}}}
The `KEEP()` ensures that a garbage collection by the linker will not
discard the content of this section. This would be normally the case
since the linker set items are not referenced directly. The `SORT()`
directive sorts the input sections lexicographically. Please note the
lexicographical order of the `.begin`, `.content` and `.end` section name
parts in the previous example which ensures that the position of the begin
and end markers are right. The interesting part of linker map file of the
previous example may look like this.
{{{
.rtemsroset 0x0000000001001990 0x4 load address
0x000000000002268c
*(SORT(.rtemsroset.*))
.rtemsroset.myset.begin
0x0000000001001990 0x0 init.o
.rtemsroset.myset.content
0x0000000001001990 0x4 module.o
.rtemsroset.myset.end
0x0000000001001994 0x0 init.o
}}}
So what is the benefit of using linker sets to initialize modules?
Currently in RTEMS all available managers (semaphore, message queue,
barrier, etc.) are initialized since the initialization code doesn't know
what is actually used by the application. With the linker set approach we
need to initialize only those managers that are used by the application.
In case an application uses message queues, then it must call
`rtems_message_queue_create()`. In the module implementing this function
we can place a linker set item and register the message queue handler
constructor. Otherwise, in case the application doesn't use message
queues, then there will be no reference to the
`rtems_message_queue_create()` function and the constructor is not
registered, thus nothing of the message queue handler will be in the final
executable.
--
Ticket URL: <http://devel.rtems.org/ticket/2408>
RTEMS Project <http://www.rtems.org/>
RTEMS Project
More information about the bugs
mailing list