C++ 链接器有什么作用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3322911/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What do linkers do?
提问by Kristina Brooks
I've always wondered. I know that compilers convert the code you write into binaries but what do linkers do? They've always been a mystery to me.
我一直想知道。我知道编译器会将您编写的代码转换为二进制文件,但是链接器会做什么?他们对我来说一直是个谜。
I roughly understand what 'linking' is. It is when references to libraries and frameworks are added to the binary. I don't understand anything beyond that. For me it "just works". I also understand the basics of dynamic linking but nothing too deep.
我大致了解什么是“链接”。这是对库和框架的引用被添加到二进制文件的时候。我不明白除此之外的任何事情。对我来说它“只是有效”。我也了解动态链接的基础知识,但没有太深。
Could someone explain the terms?
有人能解释一下条款吗?
回答by Icemanind
To understand linkers, it helps to first understand what happens "under the hood" when you convert a source file (such as a C or C++ file) into an executable file (an executable file is a file that can be executed on your machine or someone else's machine running the same machine architecture).
要了解链接器,首先要了解将源文件(例如 C 或 C++ 文件)转换为可执行文件(可执行文件是可以在您的机器上执行的文件或其他人的机器运行相同的机器架构)。
Under the hood, when a program is compiled, the compiler converts the source file into object byte code. This byte code (sometimes called object code) is mnemonic instructions that only your computer architecture understands. Traditionally, these files have an .OBJ extension.
在后台,当编译程序时,编译器将源文件转换为目标字节码。此字节码(有时称为目标代码)是只有您的计算机体系结构才能理解的助记指令。传统上,这些文件具有 .OBJ 扩展名。
After the object file is created, the linker comes into play. More often than not, a real program that does anything useful will need to reference other files. In C, for example, a simple program to print your name to the screen would consist of:
创建目标文件后,链接器开始发挥作用。通常情况下,一个真正的程序在做任何有用的事情时都需要引用其他文件。例如,在 C 中,一个将您的名字打印到屏幕上的简单程序包括:
printf("Hello Kristina!\n");
When the compiler compiled your program into an obj file, it simply puts a reference to the printf
function. The linker resolves this reference. Most programming languages have a standard library of routines to cover the basic stuff expected from that language. The linker links your OBJ file with this standard library. The linker can also link your OBJ file with other OBJ files. You can create other OBJ files that have functions that can be called by another OBJ file. The linker works almost like a word processor's copy and paste. It "copies" out all the necessary functions that your program references and creates a single executable. Sometimes other libraries that are copied out are dependent on yet other OBJ or library files. Sometimes a linker has to get pretty recursive to do its job.
当编译器将您的程序编译成 obj 文件时,它只是简单地放置了对该printf
函数的引用。链接器解析此引用。大多数编程语言都有一个标准的例程库来涵盖该语言所期望的基本内容。链接器将您的 OBJ 文件与此标准库链接。链接器还可以将您的 OBJ 文件与其他 OBJ 文件链接起来。您可以创建具有可由另一个 OBJ 文件调用的函数的其他 OBJ 文件。链接器的工作原理几乎就像文字处理器的复制和粘贴。它“复制”出您的程序引用的所有必要函数并创建一个可执行文件。有时,复制出的其他库依赖于其他 OBJ 或库文件。有时,链接器必须非常递归才能完成其工作。
Note that not all operating systems create a single executable. Windows, for example, uses DLLs that keep all these functions together in a single file. This reduces the size of your executable, but makes your executable dependent on these specific DLLs. DOS used to use things called Overlays (.OVL files). This had many purposes, but one was to keep commonly used functions together in 1 file (another purpose it served, in case you're wondering, was to be able to fit large programs into memory. DOS has a limitation in memory and overlays could be "unloaded" from memory and other overlays could be "loaded" on top of that memory, hence the name, "overlays"). Linux has shared libraries, which is basically the same idea as DLLs (hard core Linux guys I know would tell me there are MANY BIG differences).
请注意,并非所有操作系统都会创建单个可执行文件。例如,Windows 使用 DLL 将所有这些功能放在一个文件中。这会减少可执行文件的大小,但会使您的可执行文件依赖于这些特定的 DLL。DOS 过去使用称为 Overlays(.OVL 文件)的东西。这有很多用途,但一个是将常用函数放在一个文件中(它的另一个用途,如果您想知道的话,是能够将大型程序放入内存中。DOS 在内存方面有限制,覆盖可以从内存中“卸载”,其他覆盖可以“加载”在该内存之上,因此名称为“覆盖”)。Linux 有共享库,这与 DLL 的想法基本相同(我认识的硬核 Linux 人会告诉我有很多大的不同)。
Hope this helps you understand!
希望这能帮助你理解!
回答by Will Dean
In languages like 'C', individual modules of code are traditionally compiled separately into blobs of object code, which is ready to execute in every respect other than that all the references that module makes outside itself (i.e. to libraries or to other modules) have not yet been resolved (i.e. they're blank, pending someone coming along and making all the connections).
在像“C”这样的语言中,单独的代码模块传统上被单独编译成目标代码块,这些目标代码可以在各个方面执行,除了模块在自身外部(即对库或其他模块)进行的所有引用都具有尚未解决(即它们是空白的,等待某人出现并建立所有连接)。
What the linker does is to look at all the modules together, look at what each module needs to connect to outside itself, and look at all the things it is exporting. It then fixes that all up, and produces a final executable, which can then be run.
链接器所做的是将所有模块放在一起查看,查看每个模块需要连接到自身外部的内容,并查看它导出的所有内容。然后它修复所有这些,并生成一个最终的可执行文件,然后可以运行。
Where dynamic linking is also going on, the output of the linker is stillnot capable of being run - there are still some references to external libraries not yet resolved, and they get resolved by the OS at the time it loads the app (or possibly even later during the run).
在动态链接也在进行的情况下,链接器的输出仍然无法运行 - 仍然有一些对外部库的引用尚未解析,它们在加载应用程序时由操作系统解析(或者可能甚至在运行的后期)。
回答by Jerry Coffin
When the compiler produces an object file, it includes entries for symbols that are defined in that object file, and references to symbols that aren't defined in that object file. The linker takes those and puts them together so (when everything works right) all the external references from each file are satisfied by symbols that are defined in other object files.
当编译器生成一个目标文件时,它包括在该目标文件中定义的符号条目,以及对未在该目标文件中定义的符号的引用。链接器获取这些并将它们放在一起(当一切正常时)来自每个文件的所有外部引用都由其他目标文件中定义的符号满足。
It then combines all those object files together and assigns addresses to each of the symbols, and where one object file has an external reference to another object file, it fills in the address of each symbol wherever it's used by another object. In a typical case, it'll also build a table of any absolute addresses used, so the loader can/will "fix up" the addresses when the file is loaded (i.e., it'll add the base load address to each of those addresses so they all refer to the correct memory address).
然后它将所有这些目标文件组合在一起并为每个符号分配地址,并且当一个目标文件具有对另一个目标文件的外部引用时,它会在每个符号被另一个对象使用的地方填充它的地址。在典型的情况下,它还会构建一个包含所使用的任何绝对地址的表,因此加载器可以/将在加载文件时“修复”地址(即,它会将基本加载地址添加到每个地址中)地址,因此它们都指向正确的内存地址)。
Quite a few modern linkers can also carry out some (in a few cases a lot) of other "stuff", such as optimizing the code in ways that are only possible once all of the modules are visible (e.g., removing functions that were included because it was possiblethat some other module might call them, but once all the modules are put together it's apparent that nothing ever calls them).
相当多的现代链接器还可以执行一些(在少数情况下很多)其他“东西”,例如以只有在所有模块都可见时才可能的方式优化代码(例如,删除包含的函数)因为它可能是一些其他的模块可能会打电话给他们,但一旦所有的模块都放在一起很明显的是,从来都没有叫他们)。