目标文件和共享目标文件之间的关系
共享对象(.so
)文件和对象(.o
)文件之间的关系是什么?
你能通过例子解释一下吗?
what is the relation between shared object(.so
) file and object(.o
) file?
can you please explain via example?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
.so 类似于 Windows 上的 .dll。 .o 与 Visual Studio 下的 .obj 完全相同。
A .so is analogous to a .dll on windows. A .o is exactly the same as a .obj under Visual Studio.
假设您有以下 C 源文件,将其命名为
name.c
当您编译它时,使用
cc name.c
生成name.o
。 .o 包含 name.c 中定义的所有函数和变量的已编译代码和数据,以及将其名称与实际代码关联的索引。 如果您查看该索引,例如使用 nm 工具(在 Linux 和许多其他 Unix 上可用),您会注意到两个条目:这意味着什么:有两个符号(函数或变量的名称,但不是存储在 .o 中的类、结构或任何类型的名称)。 第一个标记为
T
,实际上在name.o
中包含其定义。 另一个标有U
的只是一个参考。 可以在此处找到print_name
的代码,但不能找到printf
的代码。 当您的实际程序运行时,它将需要找到所有引用的符号,并在其他目标文件中查找它们的定义,以便链接在一起形成完整的程序或完整的库。 因此,目标文件是在源文件中找到的定义,转换为二进制形式,可用于放入完整的程序中。您可以将 .o 文件一一链接在一起,但您不会这样做:它们通常有很多,并且它们是实现细节。 您确实希望将它们全部收集到相关对象的捆绑包中,并具有易于识别的名称。 这些捆绑包称为库,它们有两种形式:静态和动态。
静态库(在 Unix 中)几乎总是以
.a
为后缀(示例包括libc.a
,它是 C 核心库,libm.a
这是 C 数学库)等等。 继续该示例,您将使用 ar rc libname.a name.o 构建静态库。 如果您在libname.a
上运行nm
,您将看到以下内容:如您所见,它主要是一个包含查找 all< 的索引的目标文件大表。 /em> 其中的名字。 就像目标文件一样,它包含每个
.o
中定义的符号以及它们引用的符号。 如果您要链接另一个 .o(例如date.o
到print_date
),您会看到与上面类似的另一个条目。如果将静态库链接到可执行文件中,它将整个库嵌入到可执行文件中。 这就像链接所有单独的
.o
文件一样。 正如您可以想象的那样,这可能会使您的程序变得非常大,尤其是当您使用(就像大多数现代应用程序一样)大量库时。动态或共享库以
.so
为后缀。 与它的静态类似物一样,它是一个大型目标文件表,引用所有已编译的代码。 您可以使用 cc -shared libname.so name.o 来构建它。 不过,用 nm 来看与静态库有很大不同。 在我的系统上,它包含大约两打符号,其中只有两个是print_name
和printf
:共享库在一个非常重要的方面不同于静态库:它不嵌入本身在您的最终可执行文件中。 相反,可执行文件包含对共享库的引用,该引用不是在链接时而是在运行时解析的。 这有很多优点:
有一些缺点:
(如果你仔细想想,其中很多都是程序使用或不使用引用和指针而不是直接将类的对象嵌入到其他对象中的原因。这个类比非常直接。)
好的,这是很多细节,我跳过了很多内容,例如链接过程的实际工作原理。 我希望你能遵循它。 如果没有要求澄清。
Let's say you have the following C source file, call it
name.c
When you compile it, with
cc name.c
you generatename.o
. The .o contains the compiled code and data for all functions and variables defined in name.c, as well as index associated their names with the actual code. If you look at that index, say with thenm
tool (available on Linux and many other Unixes) you'll notice two entries:What this means: there are two symbols (names of functions or variables, but not names of classes, structs, or any types) stored in the .o. The first, marked with
T
actually contains its definition inname.o
. The other, marked withU
is merely a reference. The code forprint_name
can be found here, but the code forprintf
cannot. When your actual program runs it will need to find all the symbols that are references and look up their definitions in other object files in order to be linked together into a complete program or complete library. An object file is therefore the definitions found in the source file, converted to binary form, and available for placing into a full program.You can link together .o files one by one, but you don't: there are generally a lot of them, and they are an implementation detail. You'd really prefer to have them all collected into bundles of related objects, with well recognized names. These bundles are called libraries and they come in two forms: static and dynamic.
A static library (in Unix) is almost always suffixed with
.a
(examples includelibc.a
which is the C core library,libm.a
which is the C math library) and so on. Continuing the example you'd build your static library withar rc libname.a name.o
. If you runnm
onlibname.a
you'll see this:As you can see it is primarily a big table of object files with an index finding all the names in it. Just like object files it contains both the symbols defined in every
.o
and the symbols referred to by them. If you were to link in another .o (e.g.date.o
toprint_date
), you'd see another entry like the one above.If you link in a static library into an executable it embeds the entire library into the executable. This is just like linking in all the individual
.o
files. As you can imagine this can make your program very large, especially if you are using (as most modern applications are) a lot of libraries.A dynamic or shared library is suffixed with
.so
. It, like its static analogue, is a large table of object files, referring to all the code compiled. You'd build it withcc -shared libname.so name.o
. Looking at withnm
is quite a bit different than the static library though. On my system it contains about two dozen symbols only two of which areprint_name
andprintf
:A shared library differs from a static library in one very important way: it does not embed itself in your final executable. Instead the executable contains a reference to that shared library that is resolved, not at link time, but at run-time. This has a number of advantages:
There are some disadvantages:
(If you think about it many of these are the reasons programs use or do not use references and pointers instead of directly embedding objects of a class into other objects. The analogy is pretty direct.)
Ok, that's a lot of detail, and I've skipped a lot, such as how the linking process actually works. I hope you can follow it. If not ask for clarification.