¿Cómo se obtienen las direcciones inicial y final de una sección ELF personalizada?

5 minutos de lectura

avatar de usuario
mgalgs

Estoy trabajando en C en Linux. He visto el uso de gcc __section__ atributo (especialmente en el kernel de Linux) para recopilar datos (generalmente punteros de función) en secciones ELF personalizadas. ¿Cómo se recuperan y utilizan las “cosas” que se colocan en esas secciones personalizadas?

  • Posiblemente de interés: stackoverflow.com/questions/4152018/…

    – Ben Jackson

    14 mayo 2013 a las 20:59

  • Mejor que una respuesta: mgalgs.github.io/2013/05/10/…

    – oliva

    19 de diciembre de 2018 a las 22:24

avatar de usuario
mgalgs

Siempre que el nombre de la sección resulte en un nombre de variable C válido, gcc (ldmás bien) genera dos variables mágicas: __start_SECTION y __stop_SECTION. Se pueden usar para recuperar las direcciones de inicio y final de una sección, así:

/**
 * 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 */
}

No pude encontrar ninguna documentación formal para esta función, solo algunas referencias oscuras a la lista de correo. Si sabe dónde están los documentos, ¡deje un comentario!

Si está utilizando su propio script de enlace (como lo hace el kernel de Linux), tendrá que agregar las variables mágicas usted mismo (consulte vmlinux.lds.[Sh] y esta respuesta SO).

Ver aquí para ver otro ejemplo del uso de secciones ELF personalizadas.

  • También puede usar Objdump -d

    – Magn3s1um

    14 mayo 2013 a las 20:57

  • Nota: supuse que el problema del “nombre de variable C válido” podría evitarse usando asm("__start_invalid.c.variable.name")pero resulta que no funciona.

    – o11c

    23 de junio de 2016 a las 7:33

  • Pregunta tonta: ¿Cómo haces que el enlazador coloque el símbolo de parada al final de la sección real, y no justo después del símbolo de inicio?

    – MarcusJ

    13 de noviembre de 2021 a las 9:24

Recopilando la información de varias respuestas, aquí hay un ejemplo práctico de cómo recopilar información en una sección de enlace personalizado y luego leer la información de esa sección usando las variables mágicas __start_SECTION y __stop_SECTION en su programa C, donde SECTION es el nombre de la sección en el mapa de enlaces.

los __start_SECTION y __stop_SECTION las variables están disponibles por el enlazador tan explícito extern es necesario crear referencias para estas variables cuando se utilizan desde el código C.

También hay algunos problemas si la alineación utilizada por el compilador para calcular los desplazamientos de puntero/matriz es diferente de la alineación de los objetos empaquetados en cada sección por el enlazador. Una solución (usada en este ejemplo) es almacenar solo un puntero a los datos en la sección del enlazador.

#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;
}

  • ¿Qué sucede si los nombres de las secciones no son nombres de variables válidos en C?

    – Todd liberado

    12 de abril de 2019 a las 2:53

  • @ToddFreed ¿Tiene un ejemplo de un nombre de sección que no es un nombre de variable válido en C?

    – ChrisM

    15 abr 2019 a las 20:54

  • “.note.gnu.build-id” no es un nombre de variable válido. Esta es una sección creada por ld cuando se especifica la opción –build-id, consulte linux.die.net/man/1/ld

    – Todd liberado

    16 de abril de 2019 a las 16:34

  • Pregunta tonta: ¿Cómo haces que el enlazador coloque el símbolo de parada al final de la sección real, y no justo después del símbolo de inicio?

    – MarcusJ

    13 de noviembre de 2021 a las 9:25

El enlazador puede usar los símbolos definidos en el código y puede asignar sus valores iniciales si usa el nombre exacto en la secuencia de comandos del enlazador:

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

Simplemente defina una variable en código C:

const void * _smysection;

Y luego puede acceder a eso como una variable regular.

u32 someVar = (u32)&_smysection;

  • Esta era la respuesta que necesitaba. He estado usando secciones de enlaces por un tiempo, pero quería comenzar a dividirlas en subsecciones (p. ej. .init.subsection). Los puntos en el nombre de la sección impidieron que el enlazador continuara con el genérico __start/stop etiquetas. Pero solo proporcionar las etiquetas directamente en el script del enlazador fue una solución a este problema.

    – sherrellbc

    19/11/2021 a las 15:50

Así que la respuesta anterior, __start_SECTION y __stop_SECTION funcionará, sin embargo, para que el programa pueda usar la información del enlazador, debe declarar esas variables como extern char* __start_SECTION. ¡Disfrutar!

extern char * __start_blobby;

...
printf("This section starts at %p\n", (unsigned int)&__start_blobby);
...

Hola: así.

extern const struct pseudo_ta_head __start_ta_head_section;
extern const struct pseudo_ta_head __stop_ta_head_section;    

const struct pseudo_ta_head *start = &__start_ta_head_section;
const struct pseudo_ta_head *end = &__stop_ta_head_section;

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad