看到一个代码自定义段实现如下:
typedef void (*myown_call)(void);
#define func_init(func) \
__attribute__((section("myown"), aligned(__alignof__(myown_call)))) \
myown_call _fn_##func = func
extern myown_call __start_myown;
extern myown_call __stop_myown;
void do_initcalls(void) {
myown_call *pfun = &__start_myown;
do {
(*pfun)();
++pfun;
} while (pfun < &__stop_myown);
}
上面的代码是实现初始化逻辑的,我在网上看到要想实现自定义的段数据加载,需要在链接脚本中指定__start_myown 和__stop_myown 的地址位置,但是在代码的编译过程中没有看到相关的设置,不太清楚__start_myown 、__stop_myown 的地址编译器是如何分配的,又懂得大佬可以给解释下么?
1
lechain 2023-11-22 14:35:06 +08:00
__start_myown ,__stop_myown 地址是编译器自动分配的,根据链接脚本里面为自定义的 section 节设置起始和结束地址来决定,如果不设置编译器则会自动按预设的规则选择和调整起始地址,
话说你的需求是在程序开始前只调用一次自定义初始化还是需要为多个函数的进入设置不同的初始化函数,如果是前者的话,其实 gcc 的拓展可以很容易满足需求,使用 __attribute((constructor)) 修饰函数即可。 https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Function-Attributes.html 没必要重复一遍 gcc 已经做过的工作(除非是出于学习的目的)。 |
2
kkkbbb OP @lechain 编译器就是根据__start_myown 、__stop_myown 这两个变量的先后顺序,把首地址和尾地址进行分配的?变量名也可以随便起?
|
3
kkkbbb OP @lechain 我可能上面没说清楚,我现在没有看到环境里有自定义的链接脚本,但是我看到网上都是先通过自定义链接脚本,定义好首尾地址的位置使用的,所以我才会有疑惑,这个收尾地址编译器可以自动分配?但是它怎么知道分配给那个变量,还有首尾地址的先后顺序如何确定的?
|
4
kkkbbb OP 我刚写了个 demo 试了下,变量改变名称就会有问题,感觉应该是利用了编译器编译过程的默认变量处理实现的,有没有大佬懂为啥呢?
|
5
colorglass 2023-11-22 17:12:34 +08:00
可能它编译使用的链接脚本中主动加了相关 symbol,可以在编译时加上 -Wl,--verbose 看看它编译过程中使用的连接脚本。或者如果这两个 symbol 是 gcc 自动加入的,可以在编译时加上 -v 来看看编译时使用了哪些相关的 flag 。我个人测试使用默认 flag 与链接脚本的情况下 gcc 会在.text 后自动添加自定义的 section,但不会添加对应的头尾 symbol 。
|
6
colorglass 2023-11-22 17:16:24 +08:00
@colorglass 感觉应该是自定义的链接脚本,gcc 对 section 头尾 symbol 名称的格式一般是 "__section_start, __section_end",不会用"stop"。
|
7
sbldehanhan 2023-11-22 17:26:47 +08:00
一只菜鸡纯路过。只想说太硬核了。
|
8
kkkbbb OP @sbldehanhan 一样,看有没有大佬了解
|
9
kkkbbb OP @colorglass 没有,你可以用这段代码自己试下,就是自动生成的 symbol
|
10
kkkbbb OP @colorglass 刚才回的不太准确,如果你只定义了 section ,确实不会自动生成 symbol ,但是如果使用了__start_myown ,就会生成了
|
11
lechain 2023-11-22 18:03:16 +08:00
在链接脚本导出一下就好了,
```link SECTIONS { /* .... */ .myown : { PROVIDE(__start_myown = .); *(.myown) PROVIDE(__stop_myown = .); } /* .... */ } ``` 如果一个东西不确定工具软件会不会帮你生成,你就当作不会,然后自己写,这是最快的 |
12
koebehshian 2023-11-22 18:07:50 +08:00
我看 RT-Thread ( https://club.rt-thread.org/ask/article/d686458bbba864f4.html) 是用不同的段名表示 start 与 end ,以及执行的初始化函数,也就是有 3 个 section ,按 ASCII 排序的。
|
13
koebehshian 2023-11-22 22:05:36 +08:00
我测试了一下,是按定义的顺序排的,并不是名称的 ASCII 码,RT-Thread 的链接脚本把段排序了:
https://github.com/RT-Thread/rt-thread/blob/896b1fe2dac161a24281cb0b0de92ede3f462778/bsp/stm32/libraries/templates/stm32f10x/board/linker_scripts/link.lds#L42 |
14
icyalala 2023-11-22 22:34:39 +08:00 2
这东西一般叫 linker magic, 由编译器 linker 实现的,有些人会拿来做编译期的注册制。
MSVC: https://devblogs.microsoft.com/oldnewthing/20181107-00/?p=100155 GCC/Clang: https://sourceware.org/binutils/docs/ld/Input-Section-Example.html |
15
zhdi 2023-11-23 03:46:31 +08:00 via iPhone
@lechain 正确的,上面的全在不知道说什么东西(
另外题主问这种问题请把所有代码都放出来以供参考,这种底层的东西经常是一个 shit 糊另一个 shit ,并且没有那么明显的糊的痕迹,如果你的能力并不足以锁定代码位置就把相关的全扔出来,起码搞个链接 |
16
kkkbbb OP |