21

我在 Linux 上使用 C 语言工作。我已经看到使用 gcc__section__属性(尤其是在 Linux 内核中)将数据(通常是函数指针)收集到自定义 ELF 部分中。如何检索和使用这些自定义部分中的“东西”?

4

5 回答 5

26

只要节名产生一个有效的 C 变量名,gcc(ld而是) 生成两个魔术变量:__start_SECTION__stop_SECTION. 这些可用于检索节的开始和结束地址,如下所示:

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

我找不到任何有关此功能的正式文档,只有一些晦涩的邮件列表引用。如果您知道文档在哪里,请发表评论!

如果您使用自己的链接器脚本(如 Linux 内核那样),您必须自己添加魔法变量(参见vmlinux.lds.[Sh]这个 SO 答案)。

有关使用自定义 ELF 部分的另一个示例,请参见此处

于 2013-05-14T20:57:00.440 回答
12

从各种答案中收集信息,这里是一个工作示例,说明如何将信息收集到自定义链接器部分,然后使用魔术变量__start_SECTION__stop_SECTIONC 程序从该部分读取信息,其中SECTION部分的名称是链接地图。

和变量由链接器提供,因此当从 C 代码中使用这些变量时,需要为这些变量创建显式__start_SECTION引用。__stop_SECTIONextern

如果编译器用于计算指针/数组偏移的对齐方式与链接器在每个部分中打包的对象的对齐方式不同,也会出现一些问题。一种解决方案(在此示例中使用)是仅在链接器部分中存储指向数据的指针。

#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;
}
于 2018-01-31T19:59:40.577 回答
5

链接器可以使用代码中定义的符号,并且如果您在链接器脚本中使用确切的名称,则可以分配它们的初始值:

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

只需在 C 代码中定义一个变量:

const void * _smysection;

然后您可以将其作为常规变量进行访问。

u32 someVar = (u32)&_smysection;
于 2015-07-23T12:11:53.923 回答
0

__start_SECTION因此,上面的答案__stop_SECTION将起作用,但是要使程序能够使用来自链接器的信息,您需要将这些变量声明为extern char* __start_SECTION. 享受!

extern char * __start_blobby;

...
printf("This section starts at %p\n", (unsigned int)&__start_blobby);
...
于 2017-08-16T18:00:29.437 回答
0

嗨:像这样。

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;
于 2019-02-23T05:40:15.017 回答