包含Linux GCC链接器

我不明白GCC如何在Linux下工作。 在源文件中,当我做一个:

#include <math.h> 

编译器是否提取了相应的二进制代码并将其插入到编译的可执行文件中?编译器是否插入了对外部二进制文件(a-la Windows DLL?)的引用?

我猜这个问题的一个通用版本是:是否有一个等效的概念,以* nix下的Windows DLL?

Solutions Collecting From Web of "包含Linux GCC链接器"

好。 如果包含math.h ,编译器将读取包含可以使用的函数和宏的声明的文件。 如果您调用在该文件( 文件)中声明的函数,那么编译器会将一个调用指令插入到您的目标文件中的将由您编译的文件创建的地方(让我们将其称为test.c然后创建test.o对象文件) test.o )。 它还向该对象文件的重定位表添加条目:

 Relocation section '.rel.text' at offset 0x308 contains 1 entries: Offset Info Type Sym.Value Sym. Name 0000001c 00000902 R_386_PC32 00000000 bar 

这将是一个功能栏的重定位条目。 符号表中的条目将会被记录下来,注意到函数尚未定义:

 9: 00000000 0 NOTYPE GLOBAL DEFAULT UND bar 

test.o目标文件链接到程序时,需要链接到名为libm.so的数学库。 so扩展名与Windows的.dll扩展名相似。 这意味着它是一个共享的对象文件 。 编译器在链接时会修正出现在test.o重定位表中的所有地方,用条形函数的正确地址替换它的条目。 这取决于你是使用库的共享版本还是使用静态的(它被称为libm.a ),编译器会在编译之后修改,或者在运行的时候,当你真正启动你的程序的时候。 完成后,它将在该程序所需的共享库表中注入一个条目。 (可以用readelf -d ./test ):

 Dynamic section at offset 0x498 contains 22 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libm.so.6] 0x00000001 (NEEDED) Shared library: [libc.so.6] ... ... ... 

现在,如果你启动你的程序,动态链接器将查找该库,并将该库链接到你的可执行映像。 在Linux中,这样做的程序被称为ld.so 静态库在动态部分中没有位置,因为它们只是链接到其他对象文件,然后被遗忘; 他们是从那时起的可执行文件的一部分。

实际上它实际上要复杂得多,我也不明白这一点。 虽然这是粗略的计划。

这里涉及几个方面。

首先是头文件 。 编译器只是简单地将文件的内容包含在所包含的位置,仅此而已。 据我所知,GCC甚至不以不同的方式处理标准头文件(但我可能在那里是错的)。

但是,头文件实际上可能不包含实现,只有它的声明。 如果实现位于其他地方,则必须告诉编译器/链接器。 默认情况下,只需将相应的库文件传递给编译器,或者传递一个库名即可。 例如,以下两个是等价的(假定libcurl.a驻留在链接器可以找到的目录中):

 gcc codefile.c -lcurl gcc codefile.c /path/to/libcurl.a 

这告诉链接编辑器 (“链接器”)将您的代码文件链接到静态库libcurl.a的实现(编译器gcc实际上忽略了这些参数,因为它不知道如何处理这些参数,只是传递它们到链接器)。 但是,这被称为静态链接 。 还有一些动态链接 ,这些链接发生在程序启动时,以及Windows下的.dll文件(静态库对应于Windows上的.lib文件)。 Linux下的动态库文件通常具有文件扩展名.so

了解更多关于这些文件的最好方法是熟悉GCC链接器ld以及优秀的工具集binutils ,您可以毫不费力地编辑/查看库文件(实际上是任何二进制代码文件)。

在* nix下是否有与Windows DLL类似的概念?

是的,他们被称为“共享对象”或.so文件。 它们在运行时动态链接到你的二进制文件。 在linux中,你可以在你的可执行文件上使用“ldd”命令来查看你的二进制文件链接到哪个共享对象。 您可以使用sysinternals中的ListDLLs在Windows中完成同样的事情。

编译器可以随心所欲地执行任何操作,只要实际上就像包含文件一样。 (我所知道的所有编译器,包括GCC,都只包含一个名为math.h的文件)

不,它通常不包含函数定义本身。 这是libm.so,一个“共享对象”,类似于windows .DLL。 它应该在每个系统上,因为它是libc.so的伴侣,C运行时。

编辑:这就是为什么你必须传递-lm到链接器,如果你使用数学函数 – 它指示它链接到libm.so.

有。 include包括头文件(这是标准的C / C ++行为)。 你正在寻找的是链接器 。 gcc / g ++的-l参数告诉链接器添加什么库。对于数学(libm.so),你可以使用-lm。 常见的模式是:

  • 源文件:#include <foo.h>
  • gcc / g ++命令行:-lfoo
  • 共享库:libfoo.so

math.h是这个主题的一个小的变化。