C语言 如何强制链接器拒绝特定库,而不会使库本身发生冲突



我正在尝试在链接阶段添加健全性检查。 具体来说,我有静态链接库的程序。 某些程序仅限于允许链接的库集,而其他程序则不然。 例如,假设我有两个程序分别来自food.cfruits.c,并且我有两个库(我有源代码)apple.abroccoli.aapple.abroccoli.a之间没有依赖关系。

有没有办法修改我的源代码和库的源代码,以便链接器允许我将apple.abroccoli.a链接到food.c中,并允许我将apple.a链接到fruits.c,但是当我尝试将apple.a加载并broccoli.a(或只是broccoli.a)fruits.c时会产生链接器错误? 假设我的源代码没有#include它们链接的库中的任何标头,因为它们是错误链接的,是已删除代码遗留下来的,函数原型是手动声明的,等等。

如果我能以某种方式标记这些库,以便我的程序可以拒绝特定标记,那就太好了。

我使用的特定编译器没有实现#pragma poison,这确实是我在搜索中找到的唯一有用的工具。 我的直觉告诉我,我可以用弱符号做一些聪明的事情,但我不确定是什么或如何做。

我也不相信使用#define会对我有帮助,因为我的理解是这只会阻止我#include特定文件,但如果我弄错了,那么这也是一个很好的解决方案。

某些程序仅限于允许链接的库集,而其他程序则不然。

这没有多大意义。

有没有办法修改我的源代码和库的源代码,例如 链接器将允许我将apple.abroccoli.a链接到food.c,并将允许我将apple.a链接到fruits.c,但会 当我尝试加载apple.abroccoli.a时产生链接器错误(或 只是broccoli.a)进入fruits.c

不,因为 C 语言对库一无所知。 它的规范以一种允许实现提供和使用它们的方式编写,但在 C 语言中没有办法引用库本身。 它不是C概念。

无论如何,这没有多大意义。 静态库名称没有固有的意义。 它们只有在识别其内容时才有意义。 不允许fruits.c链接broccoli.a没有任何好处,因为它很容易解决,并且可以想象它甚至会通过构建系统维护中的错误意外解决 -用于broccoly.a的对象被额外或代替地放入apple.a中。

此外,大多数链接器都很聪明——它们在构建可执行文件时会省略未引用的函数和对象,因此在链接中包含不需要的(静态)库通常是无害的。

好的,首先要做的是:这闻起来非常像一个围绕一个可以更容易解决的问题的大糟糕的黑客!

现在一种可能的方法是强制执行"多重定义错误"。 对于我的示例,有以下文件:

  • broccoli_mark.c用于"标记"(见下文)西兰花库。
  • broccoli_fn.c包含西兰花库的功能。
  • fruits.c哪个程序不应该链接到西兰花库。 这被"标记"为不允许与西兰花链接。

"标记">:这可以通过在这些文件中简单地定义具有某个已知名称的全局符号来实现。 例如:

int broccoli_mark; // a global variable

仅将其放入broccoli_mark.c并将其添加到fruit.c某处。

现在链接...

# Compile and ar the library
$ gcc -c broccoli_mark.c
$ gcc -c broccoli_fn.c
$ ar rcs broccoli.a broccoli_mark.o broccoli_fn.o
# Compile and link program
$ gcc -c fruits.c
$ gcc fruits.o broccoli.a

作品..仅仅是因为与静态库的链接方式:基本上,链接器只挑选(整个)对象文件,这些文件定义了当前链接集中未定义的符号(最初是程序,然后也从库中添加了对象文件)。

因此,为了链接失败,我们必须确保包含broccoli_mark.o(或更具体地说,其包含的符号broccoli_mark)。 方法:

  • 将多个对象文件"合并"为一个:

    # Merge two object files into a single broccoli.o
    $ ld -r -o broccoli.o broccoli_fn.o broccoli_mark.o
    # create the library or not ..
    $ gcc fruits.o broccoli.o
    ld: broccoli.o:(.data+0x0): multiple definition of `broccoli_mark'; fruits.o:(.data+0x0): first defined here
    collect2: error: ld returned 1 exit status
    

    是的!

    请注意,您可以对西兰花库的所有.o文件执行此操作...但是,您破坏了静态库的有用属性,只包含必要的内容。

    另请注意,有些选项可能会破坏这一点。

    (类似的替代方案:--whole-archive选项)

  • 只需将"标记"包含在肯定会包含的源文件中(例如,包含库的"main"函数的文件)。

当然,所有这些"标记"等都可以隐藏在描述性的宏名称后面......不过,仍然感觉像一个非常糟糕的黑客!

最新更新