gcc` -shared`选项如何影响输出?

时间:2014-08-01 16:37:02

标签: c gcc shared-libraries

从技术上讲,就文件内容而言,gcc -fPIC -shared src.cgcc -fPIC src.c的输出之间有什么区别?

假设在int main(int, char**)中定义了src.c,以便两个编译都成功。但是按预期执行a.out生成的gcc -shared src.c会出现以下错误:

-bash: ./a_shared.out: cannot execute binary file

即使有main功能,也可以。

另外,如何使用otoolobjdump等工具检查输出文件的差异?

非常感谢。

2 个答案:

答案 0 :(得分:7)

共享库和可执行文件使用相同的格式:它们都是可加载的图像。然而,

  1. 共享库通常与位置无关,可执行文件通常不是。这会影响代码生成:对于与位置无关的,您必须加载全局变量或使用相对地址跳转到函数。

  2. 可执行文件有一个"入口点"执行开始的地方。这通常是 not main(),因为main()是一个函数,函数返回,但执行不应该从入口点返回。

  3. 现在,这并没有回答关于-shared做什么的问题。您可以使用-v标志询问GCC。以下是我的系统在没有和-shared的调用之间的差异。

    collect2没有-shared的参数:

    -dynamic-linker
    /lib64/ld-linux-x86-64.so.2
    /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o
    /usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o
    /usr/lib/gcc/x86_64-linux-gnu/4.7/crtend.o
    

    collect2 -shared的参数:

    -shared
    /usr/lib/gcc/x86_64-linux-gnu/4.7/crtbeginS.o
    /usr/lib/gcc/x86_64-linux-gnu/4.7/crtendS.o
    

    观察

    代码生成似乎不受影响:您仍然必须使用-fpic-fPIC

    您可以看到crt1.o(" C运行时")仅在链接可执行文件时包含。使用nm,我们可以找到它包含的内容:

    $ nm /usr/lib/x86_64-linux-gnu/crt1.o
    0000000000000000 R _IO_stdin_used
    0000000000000000 D __data_start
                     U __libc_csu_fini
                     U __libc_csu_init
                     U __libc_start_main
    0000000000000000 T _start
    0000000000000000 W data_start
                     U main
    

    因此,您可以看到它似乎定义了与stdin以及_start(这是入口点)有关的内容,并且它具有对main的未定义引用。

    我不确定其余的文件是什么,但至少你知道如何找到它们,你可以四处寻找,或者如果你愿意,可以查看源代码。

答案 1 :(得分:0)

根据https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options -shared 选项执行以下操作

  
      
  • 生成一个共享对象,然后可以将其与其他对象链接以形成可执行文件。

  •   
  • 并非所有系统都支持此选项。

  •   
  • 对于可预测的结果,在指定此链接器选项时,还必须指定用于编译的同一组选项(-fpic,-fPIC或模型子选项)。

  •   

根据Difference between -shared and -Wl,-shared of the GCC options -shared 传递给GCC可能会在链接时启用或禁用其他标记。

根据我的理解,如果可执行文件具有共享库,则可执行文件的大小。在共享库存在并正确链接之前,可执行文件不会运行。使用共享库的好处是,如果我们有一个非常大的代码库,我们不需要每次都构建整个代码。我们只需要重建.so文件并将其链接到可执行文件。这可以节省大量时间

如果可执行文件没有共享库,则可执行文件大小将非常大。对于每个代码更改需要构建整个代码,这可能非常耗时