ord*_*ary 5 c c++ assembly linker compilation
我理解编译过程的方式:
1)预处理:所有宏都替换为实际值,删除所有注释等.用您包含的文件的文字文本替换#include语句.
2)编译:这里不会深入挖掘,但结果是您所在的任何架构的汇编文件.
3)汇编:获取汇编文件并将其转换为二进制指令,即机器代码.
4)链接:这是我困惑的地方.此时你有一个可执行文件.但是,如果您实际运行该可执行文件会发生什 问题是你可能包含*.h文件,那些只包含函数原型?因此,如果您实际调用这些文件中的一个函数,它将没有定义,您的程序将崩溃?
如果是这样的话,那引信到底是做什么的呢?它如何找到与您包含的.h相关联的.c文件,以及它如何将其注入到您的机器代码中?是否必须再次为该文件完成整个编译过程?
现在,我已经明白有两种类型的链接,动态和静态.当你为你创建的每个可执行文件重新编译库的源代码时是静态的吗?我不太明白动态链接是如何工作的.那么您编译一个可由您使用它的所有进程共享的可执行库?这怎么可能呢?它不会在尝试访问它的进程的地址空间之外吗?另外,对于动态链接,您是否仍需要在某个时刻编译库?是不是只是坐在那里等待使用?什么时候编译?
您是否可以通过上述内容清除所有误解,错误的假设并替换您正确的解释?
小智 12
此时你有一个可执行文件.
不.此时,您有目标文件,这些文件本身不可执行.
但是,如果您实际运行该可执行文件会发生什
像这样的东西:
h2co3-macbook:~ h2co3$ clang -Wall -o quirk.o quirk.c -c
h2co3-macbook:~ h2co3$ chmod +x quirk.o
h2co3-macbook:~ h2co3$ ./quirk.o
-bash: ./quirk.o: Malformed Mach-o file
Run Code Online (Sandbox Code Playgroud)
我告诉过你这不是一个可执行文件.
问题是你可能包含*.h文件,那些只包含函数原型?
实际上非常接近.翻译单元(.c文件)(通常)转换为汇编/机器代码,代表它的作用.如果它调用一个函数,那么文件中会引用该函数,但没有定义.
因此,如果您实际调用这些文件中的一个函数,它将没有定义,您的程序将崩溃?
正如我所说,它甚至都不会运行.让我再说一遍:目标文件不可执行.
在引擎盖下,链接究竟做了什么?它是如何找到与.h相关联的.c文件[...]
它没有.它查找从.c文件生成的其他目标文件,最终查找库(基本上只是其他目标文件的集合).
它找到它们是因为你告诉它要寻找什么.假设你有一个由两个.c文件组成的项目,它们调用彼此的函数,这将不起作用:
gcc -c file1.c -o file1.o
gcc -c file2.c -o file2.o
gcc -o my_prog file1.o
Run Code Online (Sandbox Code Playgroud)
它将因链接器错误而失败:链接器将找不到file2.c
(和file2.o
)中实现的函数的定义.但这会奏效:
gcc -c file1.c -o file1.o
gcc -c file2.c -o file2.o
gcc -o my_prog file1.o file2.o
Run Code Online (Sandbox Code Playgroud)
[...]它如何将其注入您的机器代码?
对象文件包含它们调用的函数的存根引用(通常以函数入口点地址的形式或显式的,可读的名称).然后,链接器查看每个库和目标文件,找到引用(如果找不到函数定义则抛出错误),然后用实际的"调用此函数"机器代码指令替换存根引用.(是的,这在很大程度上已经简化了,但是如果没有您询问特定的体系结构和特定的编译器/链接器,很难准确地说出来......)
当你为你创建的每个可执行文件重新编译库的源代码时是静态的吗?
否.静态链接意味着库的目标文件的机器代码实际上被复制/合并到最终的可执行文件中.动态链接意味着将库加载到内存中一次,然后在启动可执行文件时由操作系统解析上述存根函数引用.库中的机器代码不会复制到最终的可执行文件中.(所以在这里,工具链中的链接器只完成部分工作.)
以下内容可以帮助您实现启发:如果您静态链接可执行文件,它将是自包含的.它将在任何地方运行(无论如何都在兼容的架构上).如果您动态链接它,它将仅在计算机上运行,如果该特定计算机具有程序引用的所有库.
那么您编译一个可由您使用它的所有进程共享的可执行库?这怎么可能呢?它不会在尝试访问它的进程的地址空间之外吗?
操作系统的动态链接器/加载程序组件负责所有这些.
另外,对于动态链接,您是否仍需要在某个时刻编译库?
正如我已经提到的:是的,它已经编译完毕.然后它会在某个时刻(通常在第一次使用时)加载到内存中.
什么时候编译?
可以使用它之前的一段时间.通常,编译库,然后安装到系统上的某个位置,以便操作系统和编译器/链接器知道它的存在,然后就可以开始编译(嗯,链接)使用该库的程序.不早点.