Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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?

like image 735
mgalgs Avatar asked May 14 '13 20:05

mgalgs


2 Answers

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.

like image 155
mgalgs Avatar answered Sep 21 '22 13:09

mgalgs


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; } 
like image 42
ChrisM Avatar answered Sep 19 '22 13:09

ChrisM