c 语言中自定义 section 段问题请教

2023-11-22 14:05:08 +08:00
 kkkbbb

看到一个代码自定义段实现如下:

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 的地址编译器是如何分配的,又懂得大佬可以给解释下么?

1467 次点击
所在节点    C
20 条回复
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 已经做过的工作(除非是出于学习的目的)。
kkkbbb
2023-11-22 14:54:16 +08:00
@lechain 编译器就是根据__start_myown 、__stop_myown 这两个变量的先后顺序,把首地址和尾地址进行分配的?变量名也可以随便起?
kkkbbb
2023-11-22 16:42:30 +08:00
@lechain 我可能上面没说清楚,我现在没有看到环境里有自定义的链接脚本,但是我看到网上都是先通过自定义链接脚本,定义好首尾地址的位置使用的,所以我才会有疑惑,这个收尾地址编译器可以自动分配?但是它怎么知道分配给那个变量,还有首尾地址的先后顺序如何确定的?
kkkbbb
2023-11-22 16:48:35 +08:00
我刚写了个 demo 试了下,变量改变名称就会有问题,感觉应该是利用了编译器编译过程的默认变量处理实现的,有没有大佬懂为啥呢?
colorglass
2023-11-22 17:12:34 +08:00
可能它编译使用的链接脚本中主动加了相关 symbol,可以在编译时加上 -Wl,--verbose 看看它编译过程中使用的连接脚本。或者如果这两个 symbol 是 gcc 自动加入的,可以在编译时加上 -v 来看看编译时使用了哪些相关的 flag 。我个人测试使用默认 flag 与链接脚本的情况下 gcc 会在.text 后自动添加自定义的 section,但不会添加对应的头尾 symbol 。
colorglass
2023-11-22 17:16:24 +08:00
@colorglass 感觉应该是自定义的链接脚本,gcc 对 section 头尾 symbol 名称的格式一般是 "__section_start, __section_end",不会用"stop"。
sbldehanhan
2023-11-22 17:26:47 +08:00
一只菜鸡纯路过。只想说太硬核了。
kkkbbb
2023-11-22 17:38:33 +08:00
@sbldehanhan 一样,看有没有大佬了解
kkkbbb
2023-11-22 17:40:23 +08:00
@colorglass 没有,你可以用这段代码自己试下,就是自动生成的 symbol
kkkbbb
2023-11-22 17:57:24 +08:00
@colorglass 刚才回的不太准确,如果你只定义了 section ,确实不会自动生成 symbol ,但是如果使用了__start_myown ,就会生成了
lechain
2023-11-22 18:03:16 +08:00
在链接脚本导出一下就好了,

```link
SECTIONS
{
/* .... */
.myown : {
PROVIDE(__start_myown = .);
*(.myown)
PROVIDE(__stop_myown = .);
}
/* .... */
}
```

如果一个东西不确定工具软件会不会帮你生成,你就当作不会,然后自己写,这是最快的
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 排序的。
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
icyalala
2023-11-22 22:34:39 +08:00
这东西一般叫 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
zhdi
2023-11-23 03:46:31 +08:00
@lechain 正确的,上面的全在不知道说什么东西(

另外题主问这种问题请把所有代码都放出来以供参考,这种底层的东西经常是一个 shit 糊另一个 shit ,并且没有那么明显的糊的痕迹,如果你的能力并不足以锁定代码位置就把相关的全扔出来,起码搞个链接
kkkbbb
2023-11-23 09:40:33 +08:00
@zhdi 这个 demo 足以说明问题,为什么这个代码可以正常编过,并且执行:
https://imgur.com/ABhMYYV.png
kkkbbb
2023-11-23 09:41:24 +08:00
kkkbbb
2023-11-23 09:47:00 +08:00
@icyalala 多谢,大概了解了
zhdi
2023-11-23 17:28:38 +08:00
@kkkbbb sry 之前看错了 attribute 的名称,如果 attribute 的自定义 sectionname 是不带.的,linker 会自动 PROVIDE 这俩变量,但是生产中很少有人这么用,大家都是自己的 link script 然后去定义更详细的起始位置
kkkbbb
2023-11-24 09:45:25 +08:00
@zhdi 嗯嗯 学习了~

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/994162

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX