C++ 在编译系统中,链接器(ld)如何知道将myprogram.o链接到谁?
我最近读了CSAPP,对其中的编译系统部分有些怀疑 现在我们有一个使用HelloWorld.c的示例(只需打印HelloWorld)。书中说,在预处理阶段,他们用这个头文件的内容替换“#include”行。但是当我打开stdio.h时,我发现只有printf()的声明,没有具体的实现。那么在编译系统中,什么时候会引入printf()的具体实现呢 书中还说,在链接阶段,链接器(ld)链接了helloworld.o和printf.o。为什么链接器知道将我的对象文件链接到printf.o?在编译系统中,为什么它在第一步(预处理器阶段)声明此函数,并在最后一步(链接阶段)链接具体实现?为什么链接器知道将我的对象文件链接到printf.o LD知道如何搜索和找到它们。你可以看到和男人在一起的感觉: 如果共享对象依赖项不包含斜杠,则为 按以下顺序搜索:C++ 在编译系统中,链接器(ld)如何知道将myprogram.o链接到谁?,c++,c,compiler-construction,C++,C,Compiler Construction,我最近读了CSAPP,对其中的编译系统部分有些怀疑 现在我们有一个使用HelloWorld.c的示例(只需打印HelloWorld)。书中说,在预处理阶段,他们用这个头文件的内容替换“#include”行。但是当我打开stdio.h时,我发现只有printf()的声明,没有具体的实现。那么在编译系统中,什么时候会引入printf()的具体实现呢 书中还说,在链接阶段,链接器(ld)链接了helloworld.o和printf.o。为什么链接器知道将我的对象文件链接到printf.o?在编译系统中
- 使用二进制文件的DT_RPATH dynamic section属性中指定的目录(如果存在)和DT_RUNPATH属性不存在 存在。不推荐使用DT_RPATH
- 使用环境变量LD_LIBRARY_PATH,除非可执行文件正在安全执行模式下运行(请参见下文),其中 案例忽略此变量
- 使用二进制文件(如果存在)的DT_运行路径动态部分属性中指定的目录。这样的目录只会被搜索 要查找DT_所需的对象,需要(直接依赖项) 条目和不适用于这些对象的子对象,这些子对象必须 它们自己有自己的DT_运行路径条目。这与DT_RPATH不同, 用于搜索依赖关系树中的所有子级
- 从缓存文件/etc/ld.so.cache中,该文件包含以前在增强的 图书馆路径。但是,如果二进制文件与-z nodeflib链接 链接器选项时,将跳过默认路径中的共享对象。共享 安装在硬件功能目录(见下文)中的对象是 优先于其他共享对象
- 在默认路径/lib中,然后是/usr/lib。(在某些64位体系结构上,64位共享对象的默认路径是/lib64, 然后是/usr/lib64。)如果二进制文件与-z nodeflib链接 链接器选项,跳过此步骤
.h
文件。在链接阶段,只需要.o
文件
为什么链接器知道将我的对象文件链接到printf.o
因为编译器在其生成的内容(通常称为对象文件(.o))中记录了这一点
为什么它要在第一步声明这个函数
我想知道这件事
。。。并将具体实施与最后一步联系起来
因为不需要提前做这个。
< P>所有的C++和C++标准告诉你,你需要<代码>包含一个给定的头文件,以便引入一些功能(在一些平台上,即使是一个很好的想法,你也可以编写可移植代码)。 这为编译器提供了很大的灵活性 链接(如果有)将自动完成。请注意,有些函数甚至可能硬编码到编译器本身。默认情况下,每次在C程序中都会链接库(包含printf的实现)通过包含头,您只需在编译时指定(暂时)已声明函数的实现(在头内部)在其他地方。在链接阶段的后期,这些函数实现会“添加”到代码中。实际上,过于简化了:
- 您可以将函数编译到库中(例如unix上的
或.a
文件).so
- 该库有一个函数体(汇编指令)和一个函数名。例如,库
具有libc.so
函数,该函数从库文件printf
中的字符编号libc.so
开始0xaabbccdd
- 你想编译你的程序
- 您需要知道
采用的参数。需要printf
吗?是否需要int
?它至少需要24分钟吗?它在头文件中-char*
intprintf(constchar*,…)代码>。标头告诉编译器如何调用函数(函数采用什么参数以及返回什么类型)。请注意,每个
文件都是单独编译的李>.c
- 函数声明(函数接受的参数和返回的参数)不存储在库文件中。它存储在标题中(仅限)。该库具有函数名(仅
)和编译后的函数体。标头具有printf
int printf(常量字符*,…)代码>没有函数体
- 你编译你的程序。编译器生成代码,以便将具有适当大小的参数推送到堆栈上。代码从堆栈中获取函数返回的变量。现在,您的程序被编译成程序集,该程序集看起来像
将指针推送到堆栈上的“%d\n”;在堆栈上推一些int;调用printf;从堆栈中弹出返回的“int”;其余的说明代码>
- 链接器在编译的程序中搜索,它会看到
。然后它说:“Och,你的代码中没有调用printf
body”。所以printf
- 函数声明(函数接受的参数和返回的参数)不存储在库文件中。它存储在标题中(仅限)。该库具有函数名(仅