How do you get the start and end addresses of a custom ELF section?

17,925

Solution 1

As long as the section name results in a valid C variable name, gcc (ld, rather) generates two magic variables: __start_SECTION and __stop_SECTION. Those can be used to retrieve the start and end addresses of a section, like so:

/**
 * Assuming you've tagged some stuff earlier with:
 * __attribute((__section__("my_custom_section")))
 */

struct thing *iter = &__start_my_custom_section;

for ( ; iter < &__stop_my_custom_section; ++iter) {
    /* do something with *iter */
}

I couldn’t find any formal documentation for this feature, only a few obscure mailing list references. If you know where the docs are, drop a comment!

If you're using your own linker script (as the Linux kernel does) you'll have to add the magic variables yourself (see vmlinux.lds.[Sh] and this SO answer).

See here for another example of using custom ELF sections.

Solution 2

Collecting the information together from various answers, here is a working example of how to collect information into a custom linker section and then read the information from that section using the magic variables __start_SECTION and __stop_SECTION in your C program, where SECTION is the name of the section in the link map.

The __start_SECTION and __stop_SECTION variables are made available by the linker so explicit extern references need to be created for these variables when they are used from C code.

There are also some problems if the alignment used by the compiler for calculating pointer/array offsets is different than the alignment of the objects packed in each section by the linker. One solution (used in this example) is to store only a pointer to the data in the linker section.

#include <stdio.h>

struct thing {
    int val;
    const char* str;
    int another_val;
};
struct thing data1 = {1, "one"};
struct thing data2 = {2, "two"};

/* The following two pointers will be placed in "my_custom_section".
 * Store pointers (instead of structs) in "my_custom_section" to ensure
 * matching alignment when accessed using iterator in main(). */
struct thing *p_one __attribute__((section("my_custom_section"))) = &data1; 
struct thing *p_two __attribute__((section("my_custom_section"))) = &data2;

/* The linker automatically creates these symbols for "my_custom_section". */
extern struct thing *__start_my_custom_section;
extern struct thing *__stop_my_custom_section;

int main(void) {
    struct thing **iter = &__start_my_custom_section;
    for ( ; iter < &__stop_my_custom_section; ++iter) {
        printf("Have thing %d: '%s'\n", (*iter)->val, (*iter)->str);
    }
    return 0;
}

Solution 3

Linker can use the symbols defined in the code, and can assign their initial values if you use the exact name in the linker script:

_smysection = .;
*(.mysection)
*(.mysection*)
_emysection = .;

Just define a variable in C code:

const void * _smysection;

And then you can access that as a regular variable.

u32 someVar = (u32)&_smysection;
Share:
17,925
mgalgs
Author by

mgalgs

(eat 'pizza)

Updated on July 10, 2022

Comments

  • mgalgs
    mgalgs almost 2 years

    I'm working in C on Linux. I've seen the usage of of the gcc __section__ attribute (especially in the Linux kernel) to collect data (usually function pointers) into custom ELF sections. How is the "stuff" that gets put in those custom sections retrieved and used?

  • Magn3s1um
    Magn3s1um about 11 years
    You can also use Objdump -d
  • o11c
    o11c about 8 years
    Note: I guessed the "valid C variable name" problem could be avoided using asm("__start_invalid.c.variable.name"), but it turns out it does not work.
  • Todd Freed
    Todd Freed about 5 years
    What if the section names are not valid variable names in C
  • ChrisM
    ChrisM about 5 years
    @ToddFreed Do you have an example of a section name that is not a valid variable name in C?
  • Todd Freed
    Todd Freed about 5 years
    ".note.gnu.build-id" is not a valid variable name. This is a section created by ld when the --build-id option is specified, see linux.die.net/man/1/ld
  • yyny
    yyny almost 4 years
    extern <any valid type> __start_SECTION works, I see extern int __start_SECTION and extern char __start_SECTION used the most.
  • MarcusJ
    MarcusJ over 2 years
    Dumb question: How do you make the linker put the Stop symbol at the end of the actual section, and not right after the Start symbol?
  • MarcusJ
    MarcusJ over 2 years
    Dumb question: How do you make the linker put the Stop symbol at the end of the actual section, and not right after the Start symbol?
  • sherrellbc
    sherrellbc over 2 years
    This was the answer I needed. I've been using linker sections for a while now but wanted to begin sub sectioning them (e.g. .init.subsection). The periods in the section name prevented the linker from proceed the generic __start/stop labels. But just providing the labels directly in the linker script was a solution to this problem.
  • sherrellbc
    sherrellbc about 2 years
    @yyny in this case you need to take the address of the var e.g. &__start_SECTION. Otherwise you'll of course get the contents at the address and may find yourself very confused. Declaring the extern as a pointer (or array) prevents this.
  • yyny
    yyny about 2 years
    I think of it the other way around. If your variable has a pointer type, you might expect the section address to be in the variable value, whereas if your variable is a char, its more obvious that you have to take the address. Using an array type might be a good idea, though.