为什么在x86_64上编译静态库时gcc不会隐式提供-fPIC标志

时间:2010-10-18 17:00:52

标签: gcc compilation dynamic-linking static-linking gnu-toolchain

我在编译静态链接静态库的共享对象时遇到了很多问题。此问题仅出现在x84_64平台上。在x86_32上进行相同的编译工作时,我没有任何问题。

也许这是一个特定于操作系统的GCC配置,但我的研究表明它是如何在x86_64平台上运行的。无论如何,我在Ubuntu 10.04 x86_64上使用gcc 4.4.3。

如何修复问题?...确保使用-fPIC编译所有静态库依赖项。

问题1: -fpic和-fPIC有什么区别(显然-fPIC会在x86上生成更多指令)?为什么后一种类型在x86_64上下文中更相关?

问题2:我的假设是,当您链接静态代码时,您在链接时将函数硬连接到二进制文件中,为什么它需要间接级别“位置无关代码“机器提供?

问题3:现在,如果x86不需要-fpic / -fPIC来链接共享对象与静态存档,为什么在x86_64中需要它?

问题4:即使需要,为什么不隐式提供?我认为突破性变化应该是一个很大的禁忌

2 个答案:

答案 0 :(得分:44)

  1. 请参阅问题3544035。还讨论了herethere
  2. 这取决于您对静态库的用途。如果你只想将它链接到程序中,它就不需要PIC代码(libtool称之为便利库,因为你几乎可以不用它,它只是帮助你的编译过程达到合理的大小,例如)。否则,如果您打算将共享库链接到它,则需要在静态库中使用PIC代码。
  3. 请参阅问题3146744以及here
  4. 它使您的代码膨胀,因此它不是默认代码。有一点需要注意的是,当您编译单个目标文件时,GCC不知道您是否要创建一个共享库。在我的大多数小项目中,我只是将几个目标文件链接在一起,例如,不需要PIC代码。
  5. 另外,我的建议是:如果你需要担心,你做错了(或者你喜欢学习困难的方法,这很好,因为你会从经验中获得更多)。编译系统(libtool,cmake,无论你使用什么)都应该为你做。

答案 1 :(得分:0)

典型的.a静态库只是常规.o对象的集合

因此,从概念上讲,您通常可以在命令行上用完全相同的.a文件列表替换.o,而无需重新定位。

例如考虑以下minimal runnable example

a.c

#include "a.h"

int a(void) { return 1; }

a.h

#ifndef A_H
#define A_H

int a(void);

#endif

b.c

#include "b.h"

int b(void) { return 2; }

b.h

#ifndef B_H
#define B_H

int b(void);

#endif

main.c

#include <assert.h>
#include <stdlib.h>

#include "a.h"
#include "b.h"

int main(void) {
    assert(a() == 1);
    assert(b() == 2);
    return EXIT_SUCCESS;
}

编译并运行:

gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors -fPIC -c 'main.c' -o 'main.o'
gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors -fPIC -c 'a.c' -o 'a.o'
gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors -fPIC -c 'b.c' -o 'b.o'
ar rcs ab.a a.o b.o
gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors main.o ab.a -o maina.out
./maina.out

由此我们可以清楚地看到,ar只是将a.ob.o打包到ab.a中。

因此,以下命令也有效:

gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors main.o a.o b.o -o maina.out

由此可以明确地看出,.a存档中的目标文件通常不需要与位置无关。

如果需要,可以使他们的位置独立。例如将它们链接到共享库。一切都像以前一样适用:.a仅包含它们而不修改它们。

此答案也可能令人感兴趣:What is the -fPIE option for position-independent executables in gcc and ld?

在Ubuntu 20.04上测试。