Linker 什么';ld中--开始组和--整个存档之间的区别

Linker 什么';ld中--开始组和--整个存档之间的区别,linker,ld,Linker,Ld,老实说,我认为这个问题应该很简单,只要看看manld。然而,通过阅读manpage和其他人编写的代码,我发现人们可以互换使用它们,或者在他们认为传递给链接器的库的顺序可能存在问题的同时使用它们 我想知道这两个选项之间有什么区别,使用它们的最佳实践是什么 谢谢 相关链接: 在撰写本文时 告诉我们: 静态库是对象文件的存档。作为链接器输入,链接器提取进行链接所需的对象文件 所需的对象文件是那些为链接器提供符号定义的文件,链接器发现这些符号在其他输入文件中使用,没有定义。 所需的对象文件(而不是其

老实说,我认为这个问题应该很简单,只要看看
manld
。然而,通过阅读manpage和其他人编写的代码,我发现人们可以互换使用它们,或者在他们认为传递给链接器的库的顺序可能存在问题的同时使用它们

我想知道这两个选项之间有什么区别,使用它们的最佳实践是什么

谢谢

相关链接:


在撰写本文时 告诉我们:

静态库是对象文件的存档。作为链接器输入,链接器提取进行链接所需的对象文件

所需的对象文件是那些为链接器提供符号定义的文件,链接器发现这些符号在其他输入文件中使用,没有定义。 所需的对象文件(而不是其他文件)将从存档中提取并输入到链接,就像它们是数据库中的单个输入文件一样 链接命令和静态库根本没有提到

链接器通常支持一个选项(GNU ld:--WHOLEARCHIVE,MS link:/wholerchive)来覆盖 默认处理静态库,而是链接所有包含的对象文件,无论它们是否需要

静态库除了从链接中提取的对象文件外,对链接没有任何贡献,这些文件在不同的链接中可能有所不同。 它将与共享库形成对比,共享库是另一种在链接中具有完全不同角色的文件

这应该清楚地说明
——整个归档文件
的作用。
——整个存档的范围持续到
链接器命令行或直到
--没有出现完整的归档文件1

默认情况下,链接器将仅在链接器输入的命令行序列中静态库出现的每个点检查静态库。 为了解析在以后的输入中发现的符号引用,它不会返回到静态库

--启动组--终端组
选项对更改默认行为。它指示链接器检查静态库 在
中反复提到,只要这样做产生新符号引用的任何新分辨率,就可以按照该顺序进行<代码>--启动组--终末组
对患者无影响 链接器从
中的静态库中默认选择的对象文件。它将只提取和链接它所需的目标文件,除非
--whole archive
也被删除 实际上

总结如下:-

--启动组lib0.a。。。libN.a——终端组告诉链接器:继续搜索
lib0.a。。。libN.a
用于查找所需的对象文件,直到找不到为止

--整个归档lib0.a。。。libN.a——没有完整的归档文件告诉链接器:忘记你需要什么。只需链接所有
lib0.a中的所有对象文件。。。libN.a

然后您可以看到,您可以使用
--start group lib0.a成功建立的任何链接。。。libN.a--end group
也将成功使用
--整个归档lib0.a。。。libN.a--没有完整的存档
, 因为后者将链接所有必要的对象文件和所有不必要的文件,而不必费心区分它们之间的区别

但事实并非如此。以下是一个简单的例子:

x.c

#include <stdio.h>

void x(void)
{
    puts(__func__);
}
#include <stdio.h>

void y(void)
{
    puts(__func__);
}
extern void x(void);

int main(void)
{
    x();
    return 0;
}
#include <stdio.h>

void a(void)
{
    puts(__func__);
}
#include <stdio.h>

void b(void)
{
    puts(__func__);
}
extern void b(void);

void ab(void)
{
    b();
}
extern void a(void);

void ba(void)
{
    a();
}
extern void ab(void);
extern void ba(void);

void abba(void)
{
    ab();
    ba();
}
extern void abba(void);

int main(void)
{
    abba();
    return 0;
}
编译所有源文件:

$ gcc -Wall -c x.c y.c main.c
制作一个静态库,归档
x.o
y.o

ar rcs libxy.a x.o y.o
试图以错误的顺序将程序链接到
main.o
libxy.a

该操作失败,因为只发现了
main.o
中对
x
的引用 链接器在
libxy.a(x.o)
中找到
x
的定义太晚了。它到达了libxy.a
首先,没有找到它需要的对象文件。当时,它还没有联系起来 所有的目标文件都被输入到程序中,因此需要解析0个符号引用。有 考虑了<代码> LBYX.A <代码>,没有使用它,它不考虑它。

当然,正确的连接是:

$ gcc -o prog main.o libxy.a
但是如果你没有意识到你只是把链接顺序从后到前,你可以 通过
--整个存档获得成功的链接:

$ gcc -o prog -Wl,--whole-archive libxy.a -Wl,--no-whole-archive main.o
$ ./prog
x
$ gcc -o prog2 main2.o libabba.a -Wl,--whole-archive libbab.a libaba.a -Wl,--no-whole-archive -Wl,-trace
/usr/bin/x86_64-linux-gnu-ld: mode elf_x86_64
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
/usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
main2.o
(libabba.a)abba.o
(libbab.a)ba.o
(libbab.a)b.o
(libbab.a)x.o
(libaba.a)ab.o
(libaba.a)a.o
(libaba.a)y.o
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/lib/x86_64-linux-gnu/libc.so.6
(/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
很明显,你不能让它成功

$ gcc -o prog -Wl,--start-group libxy.a -Wl,--end-group main.o
main.o: In function `main':
main.c:(.text+0x5): undefined reference to `x'
collect2: error: ld returned 1 exit status
因为这与:

$ gcc -o prog libxy.a main.o
现在,这里有一个链接的示例,该链接在默认行为下失败,但可以 成功使用
--启动组--端组

a.c

#include <stdio.h>

void x(void)
{
    puts(__func__);
}
#include <stdio.h>

void y(void)
{
    puts(__func__);
}
extern void x(void);

int main(void)
{
    x();
    return 0;
}
#include <stdio.h>

void a(void)
{
    puts(__func__);
}
#include <stdio.h>

void b(void)
{
    puts(__func__);
}
extern void b(void);

void ab(void)
{
    b();
}
extern void a(void);

void ba(void)
{
    a();
}
extern void ab(void);
extern void ba(void);

void abba(void)
{
    ab();
    ba();
}
extern void abba(void);

int main(void)
{
    abba();
    return 0;
}
ba.c

#include <stdio.h>

void x(void)
{
    puts(__func__);
}
#include <stdio.h>

void y(void)
{
    puts(__func__);
}
extern void x(void);

int main(void)
{
    x();
    return 0;
}
#include <stdio.h>

void a(void)
{
    puts(__func__);
}
#include <stdio.h>

void b(void)
{
    puts(__func__);
}
extern void b(void);

void ab(void)
{
    b();
}
extern void a(void);

void ba(void)
{
    a();
}
extern void ab(void);
extern void ba(void);

void abba(void)
{
    ab();
    ba();
}
extern void abba(void);

int main(void)
{
    abba();
    return 0;
}
abba.c

#include <stdio.h>

void x(void)
{
    puts(__func__);
}
#include <stdio.h>

void y(void)
{
    puts(__func__);
}
extern void x(void);

int main(void)
{
    x();
    return 0;
}
#include <stdio.h>

void a(void)
{
    puts(__func__);
}
#include <stdio.h>

void b(void)
{
    puts(__func__);
}
extern void b(void);

void ab(void)
{
    b();
}
extern void a(void);

void ba(void)
{
    a();
}
extern void ab(void);
extern void ba(void);

void abba(void)
{
    ab();
    ba();
}
extern void abba(void);

int main(void)
{
    abba();
    return 0;
}
main2.c

#include <stdio.h>

void x(void)
{
    puts(__func__);
}
#include <stdio.h>

void y(void)
{
    puts(__func__);
}
extern void x(void);

int main(void)
{
    x();
    return 0;
}
#include <stdio.h>

void a(void)
{
    puts(__func__);
}
#include <stdio.h>

void b(void)
{
    puts(__func__);
}
extern void b(void);

void ab(void)
{
    b();
}
extern void a(void);

void ba(void)
{
    a();
}
extern void ab(void);
extern void ba(void);

void abba(void)
{
    ab();
    ba();
}
extern void abba(void);

int main(void)
{
    abba();
    return 0;
}
汇编所有资料来源:-

$ gcc -Wall a.c b.c ab.c ba.c abba.c main2.c
然后制作以下静态库:

$ ar rcs libbab.a ba.o b.o x.o
$ ar rcs libaba.a ab.o a.o y.o
$ ar rcs libabba.a abba.o
(请注意,这些旧的对象文件
x.o
y.o
在这里再次存档)

这里,
libaba.a
依赖于
libbab.a
libaba.a
。明确地
libaba.a(abba.o)
引用了
ab
,该词在
libaba.a(ab.o)
中定义; 它还引用了
ba
,这是在
libbab.a(ba.o)
中定义的。 因此,在链接顺序中,
libaba.a
必须出现在
libbab.a
libaba.a

libbab.a
依赖于
libbab.a
。具体来说,
libbab.a(ba.o)
a
的引用,其定义见
libaba(a.o)

但是
libbab.a
也依赖于
libbab.a
<代码>libaba(ab.o)
引用 到
b
,在
libbab(b.o)
中定义。两者之间存在循环依赖关系
libbab.a
libbab.a
。所以我们把其中的任何一个放在f