Gcc 是否有一种方法可以将不同文件中的多个符号组合在一起,以便在引用其中一个符号时,所有符号都链接在一起?

Gcc 是否有一种方法可以将不同文件中的多个符号组合在一起,以便在引用其中一个符号时,所有符号都链接在一起?,gcc,linker,ld,Gcc,Linker,Ld,先来点背景知识 我现在正在开发一个模块化(嵌入式)microOS,其中包含驱动程序、端口、分区和其他类似的对象,这些对象表示为结构,具有不同的“操作”结构,其中包含指向您将调用其方法的指针。没什么特别的 我有宏和链接器脚本位来实现它,这样,给定类型的所有对象(比如,所有驱动程序)尽管它们的定义分散在源文件中,但它们被作为数组处理,在flash中的某个位置,但链接器(我使用GNU GCC/LD)可以对代码中没有显式引用的对象进行垃圾收集 然而,经过几年对系统的改进和增加其灵活性后,我发现对于中小型

先来点背景知识

我现在正在开发一个模块化(嵌入式)microOS,其中包含驱动程序、端口、分区和其他类似的对象,这些对象表示为结构,具有不同的“操作”结构,其中包含指向您将调用其方法的指针。没什么特别的

我有宏和链接器脚本位来实现它,这样,给定类型的所有对象(比如,所有驱动程序)尽管它们的定义分散在源文件中,但它们被作为数组处理,在flash中的某个位置,但链接器(我使用GNU GCC/LD)可以对代码中没有显式引用的对象进行垃圾收集

然而,经过几年对系统的改进和增加其灵活性后,我发现对于中小型微控制器来说,它过于贪婪闪存。(我只使用32位的体系结构,没有太小的东西。)你可能会说,我本应该是一个例子,但我正试图走得更远,做得更好,目前我怀疑LD是否会让我这么做

我想得到的是,代码未使用的方法/函数也会被垃圾收集。目前情况并非如此,因为它们都由拥有它们的对象的指针结构引用。我希望避免使用宏配置开关,应用程序开发人员必须通过几层代码来确定当前正在使用哪些函数以及哪些函数可以安全禁用。我非常非常希望链接器的垃圾收集能让我自动化整个过程

首先,我认为我可以将每个方法结构拆分为多个部分,这样,所有端口的“探测”方法都会在一个名为.struct_probe的部分中结束,并且包装端口_probe()函数可以在该函数中引用一个零长度的对象,这样,当且仅当端口_probe()时,所有端口的探测引用都会链接起来函数在某处被调用

但我错了,对于链接器来说,“输入部分”是他垃圾收集的解决方案(因为在这一点上,内部没有更多的对齐信息,它无法利用符号和传入对象,通过重新排列包含部分的内部并缩小它来移除)不是仅通过节名标识,而是通过节名和源文件标识。因此,如果我实现了我想要实现的,那么我的任何方法都不会在最终的可执行文件中被链接,我将被烤熟

这就是我目前的处境,坦率地说,我很茫然。我想知道这里是否有人会有更好的主意,让每个方法“向后引用”包装函数,或者让函数引用其他对象,并带走所有方法,或者如标题所示,以某种方式将这些方法/部分分组(请不要将所有代码收集到一个文件中)因此,引用一个就意味着将它们全部链接起来


我对永恒的感激就在这里

由于我花了一些时间记录和试验以下线索,尽管没有成功,我想在这里展示我的发现

ELF有一个称为“组节”的功能,用于定义节组或节组,例如,如果组的一个成员节处于活动状态(因此链接),则所有节都处于活动状态

我希望这就是我问题的答案。TL;DR:不是,因为分组分区是指在模块内对分区进行分组。实际上,当前定义的唯一组类型是COMDAT组,根据定义,这些组与其他模块中定义的具有相同名称的组是独占的

关于该特性及其实现的文档很少。目前,可以找到该标准对组段的定义

GCC不提供用于操作节组(或任何类型的节标志/属性)的构造。GNU汇编程序的文档指定了如何将节影响到组

我在任何GNU文档中都没有发现关于LD处理组部分的信息。不过,有人提到了这一点

作为奖励,我发现了一种在使用GCC的C代码中指定节属性(包括分组)的方法。这是一个肮脏的黑客行为,所以当你读到这篇文章的时候,它可能已经不起作用了

显然,当你写作的时候

int bar __attribute__((section("<name>")));
int bar __attribute__((section("<name>,\"awG\",%probbits,<group> //")));
int-bar_uuuuu属性_uuuuu((部分(“”));
GCC将引号之间的内容盲目粘贴到程序集输出中:

.section    <name>,"aw"
。部分,“aw”
(如果名称与几个预定义模式中的一个匹配,则实际标志可能会有所不同。)

从这里开始,这就是代码注入的问题。如果你写信

int bar __attribute__((section("<name>")));
int bar __attribute__((section("<name>,\"awG\",%probbits,<group> //")));
int-bar\uuuu属性(节(“,\“awG\”,%probbits,/”));
你得到

.section  <name>,"awG",%progbits,<group> //"aw"
.section,“awG”、%progbits、//“aw”

工作完成了。如果您想知道为什么仅仅在单独的内联汇编语句中对节进行特征化是不够的,那么如果您这样做,您将得到一个空的分组节和一个同名的填充单独节,这在链接时不会产生任何效果。所以。

这并不完全令人满意,但由于缺乏更好的方法,这就是我所追求的:

从链接器的角度来看,要有效地合并来自多个编译单元的节,唯一的方法似乎是首先将生成的对象链接到一个大对象中,然后使用该大对象而不是小对象链接最终程序。在小对象中具有相同名称的部分将合并到大对象中

不过,这有点脏,也有一些缺点,例如,为了垃圾收集的目的,可能会合并一些您不想成为的部分,如果您想要spl,则隐藏每个部分来自哪个文件(尽管信息保留在调试部分中)