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

为什么gcc在x86_64上编译静态库时不隐式提供-fPIC标志,gcc,compilation,dynamic-linking,static-linking,gnu-toolchain,Gcc,Compilation,Dynamic Linking,Static Linking,Gnu Toolchain,我在编译静态链接到静态库的共享对象时遇到了很多问题。此问题仅在x84_64平台上出现。在x86_32上执行相同的编译工作时,我没有任何问题 也许这是一种特定于操作系统的GCC配置,但我的研究表明,这是GCC在x86_64平台上的工作方式。无论如何,我在Ubuntu 10.04 x86_64上使用GCC4.4.3 问题是如何解决的?。。。确保使用-fPIC编译所有静态库依赖项 问题1:-fpic和-fpic之间有什么区别(显然-fpic在x86上生成更多指令)?为什么后面的类型在x86_64上下文

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

也许这是一种特定于操作系统的GCC配置,但我的研究表明,这是GCC在x86_64平台上的工作方式。无论如何,我在Ubuntu 10.04 x86_64上使用GCC4.4.3

问题是如何解决的?。。。确保使用-fPIC编译所有静态库依赖项

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

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

问题3:现在,如果x86不需要-fpic/-fpic将共享对象链接到静态归档文件,为什么x86\u 64中需要它

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

  • 见问题。还进行了讨论和讨论
  • 这取决于静态库的用途。如果您只想将其链接到程序中,则不需要PIC代码(例如,libtool将其称为一个方便的库,因为您几乎可以不用它,它可以帮助您将编译过程调整到合理的大小)。否则,如果您打算针对它链接共享库,则需要在静态库中使用PIC代码
  • 另见问题和
  • 它会使代码膨胀,因此不是默认值。要看到的一点是,当您编译单个对象文件时,GCC不知道您是否要用它创建共享库。在我的大多数小项目中,我只是将几个对象文件链接在一起,例如,不需要PIC代码

  • 此外,我的建议是:如果你需要担心这一点,那就是你做错了(或者你喜欢用艰苦的方式学习,这很好,因为你会从经验中获得更多)。编译系统(libtool、cmake,无论您使用什么)都应该为您做到这一点。

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

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

    例如,考虑以下情况:

    a、 c

    a、 h

    b、 c

    b、 h

    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;
    }
    
    从中我们清楚地看到,
    ar
    只是将
    a.o
    b.o
    打包到
    ab.a

    因此,以下命令也起作用:

    gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors main.o a.o b.o -o maina.out
    
    从这一点可以清楚地看出,一般来说,归档文件中的对象文件不需要与位置无关

    如果您希望,例如将它们链接到共享库中,您可以使其位置独立。一切都像以前一样适用:
    .a
    只包含它们而不修改它们

    这个答案可能也很有趣:


    在Ubuntu 20.04上测试。

    关于问题1。-fpic和-fpic之间的区别在“如何编写共享库”中描述。寻找“两个选项中的哪一个,-fpic或-fpic必须使用”。我以前浏览过那篇文章的部分内容,我希望我可以不必提取答案(问题也有两部分,这一部分是否涵盖了这两部分?):我接受了你的答案:D我还没有机会查看你的信息。但我会调查一下,稍后会对你的回答发表评论。谢谢。第2点:当将共享代码链接到静态库时,为什么共享代码要求使用-fPIC编译静态库?我不明白,难道它不能在编译时链接过程中添加任何丢失的地址信息吗?当你将一个静态库链接到一个共享库中时,它不再涉及目标代码,所以它首先需要以正确的方式编译(使用PIC)。我面临的问题是依赖性,我自己使用cmake。Boost/protobuf和openssl都不为x86_64静态库提供fPIC。考虑到CMake,您可以在他们的用户邮件列表或此处询问。通过谷歌搜索,我发现了相关问题的讨论,所以这可能不是他们列表上的一个离题话题。
    #include "b.h"
    
    int b(void) { return 2; }
    
    #ifndef B_H
    #define B_H
    
    int b(void);
    
    #endif
    
    #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
    
    gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors main.o a.o b.o -o maina.out