静态库 (.a) 和共享库 (.so) 之间的文件格式差异?
File format differences between a static library (.a) and a shared library (.so)?
我知道有很多关于共享库和静态库的用例的问题,这个问题不是关于那个的。我问的是存储在磁盘上的文件格式的差异。
为什么问题是,两者之间有什么区别?还是完全一样,只是用法不同?
我相信它们是不一样的,因为共享库上的 运行 'nm' 需要 -D 标志。显然,它需要做一些不同的事情。为什么?
它们都是ELF文件吗?
唯一的区别是共享库可以包含一些依赖路径吗?
静态库只不过是 relocatable 对象的集合(它甚至不是 ELF,而是 ELF 的虚拟存档)。
共享库是一个独立的功能块,具有定义的接口(即符号 table)和依赖项(它是一个 ELF 文件)。
来源
我在示例中使用的源代码如下:
class T {
public:
T(int _x) : x(_x) { }
T& operator=(const T& rhs) { x = rhs.x; return *this; }
int getX() const { return x; }
private:
int x = 0;
};
正在创建共享库
$ g++ -shared -fPIC -c test.cpp -o test.out && ld -o libtest.so test.out
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078
正在创建静态库
$ g++ -fPIC -c test.cpp -o test.out && ar rcs libtest.a test.out
都是ELF文件吗?
有点...这是共享库的 readelf -h
的输出:
$ readelf -h libtest.so
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400078
Start of program headers: 64 (bytes into file)
Start of section headers: 408 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 1
Size of section headers: 64 (bytes)
Number of section headers: 5
Section header string table index: 2
静态库输出很相似,但不完全相同:
$ readelf -h libtest.a
File: libtest.a(test.out)
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 360 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 9
Section header string table index: 6
首先跳出的是静态库中的File
入口。它不是 ELF 对象,而是 包含 ELF 对象。确认这一点的另一种方法是查看带有 hexdump -C
(截断)的文件。一、共享库:
$ hexdump -C libtest.so
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 3e 00 01 00 00 00 78 00 40 00 00 00 00 00 |..>.....x.@.....|
00000020 40 00 00 00 00 00 00 00 98 01 00 00 00 00 00 00 |@...............|
00000030 00 00 00 00 40 00 38 00 01 00 40 00 05 00 02 00 |....@.8...@.....|
00000040 51 e5 74 64 06 00 00 00 00 00 00 00 00 00 00 00 |Q.td............|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000070 10 00 00 00 00 00 00 00 47 43 43 3a 20 28 47 4e |........GCC: (GN|
我们可以在这里非常清楚地看到字符序列 ELF
,就在文件的开头。这是静态库输出:
$ hexdump -C libtest.a
00000000 21 3c 61 72 63 68 3e 0a 2f 20 20 20 20 20 20 20 |!<arch>./ |
00000010 20 20 20 20 20 20 20 20 31 34 38 35 34 36 31 31 | 14854611|
00000020 36 36 20 20 30 20 20 20 20 20 30 20 20 20 20 20 |66 0 0 |
00000030 30 20 20 20 20 20 20 20 34 20 20 20 20 20 20 20 |0 4 |
00000040 20 20 60 0a 00 00 00 00 74 65 73 74 2e 6f 75 74 | `.....test.out|
00000050 2f 20 20 20 20 20 20 20 31 34 38 35 34 36 31 31 |/ 14854611|
00000060 36 36 20 20 31 30 30 30 20 20 31 30 30 30 20 20 |66 1000 1000 |
00000070 31 30 30 36 36 34 20 20 39 33 36 20 20 20 20 20 |100664 936 |
00000080 20 20 60 0a 7f 45 4c 46 02 01 01 00 00 00 00 00 | `..ELF........|
00000090 00 00 00 00 01 00 3e 00 01 00 00 00 00 00 00 00 |......>.........|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 68 01 00 00 |............h...|
000000b0 00 00 00 00 00 00 00 00 40 00 00 00 00 00 40 00 |........@.....@.|
000000c0 09 00 06 00 00 47 43 43 3a 20 28 47 4e 55 29 20 |.....GCC: (GNU)
我们可以在 ELF 头开始之前看到一堆额外的东西,证实了我们的假设,即静态库与共享库的存储方式不同。
另一个区别是 Type
条目;共享库被标记为可执行,而静态库则不是。事实上,共享库和可执行文件之间根本没有太大区别:https://askubuntu.com/questions/690631/executables-vs-shared-objects
静态库,例如libfoo.a
不是任何类型的 executable。
它只是 unix ar
format 中的索引存档
恰好是 ELF 的其他文件
目标文件。
像任何存档一样创建静态库:
ar crs libfoo.a objfile0.o objfile1.0...objfileN.o
输出新存档(c
)libfoo.a,插入目标文件(r
)
并添加了索引 (s
).
您会在程序中听到 linking libfoo.a
。这并不意味着
libfoo.a
本身 被 link 编入程序或与程序一起编入。这意味着 libfoo.a
作为存档传递给 linker,它可以从中提取并 link
该程序只是程序需要的存档中的那些目标文件。
所以静态库的格式(ar
格式)只是一个object-file
linker 输入的捆绑格式:它同样可以是其他一些捆绑
格式对 linker 的任务没有任何影响,即消化一组
目标文件和共享库并生成程序或共享库,
从他们。 ar
格式是历史的选择。
另一方面,共享库,例如libfoo.so
、是一个ELF文件
而不是任何类型的存档。
不要怀疑静态库是一种 ELF 文件
事实上,所有 well-known ELF-parsers - objdump
、readelf
、nm
-
将解析一个静态库。这些工具都知道静态库是
个 ELF 对象文件的存档,因此它们只解析所有对象文件
在库中,就像您在命令行中列出它们一样。
将 -D
选项与 nm
一起使用只是指示工具 select
只有动态交易品种 table(s) 中的交易品种,如果有的话,
它解析的 ELF 文件的数量 - 运行时间 linker 可见的符号
- 无论它们是否从存档中解析。它是
与 objdump -T
和 readelf --dyn-syms
相同。 不是
必须使用这些选项来解析共享库中的符号。如果
如果您不这样做,那么默认情况下您只会看到 完整 符号 table。
如果您 运行 nm -D
在静态库上,您将被告知 no symbols
,因为
存档中的每个目标文件 - 同样,如果您 运行 nm -D
每个
这些目标文件单独。原因是目标文件
没有动态符号 table:只有共享库或程序有一个。
目标文件、共享库和程序都是ELF格式的变体。
如果您对 ELF 变体感兴趣,这些是您感兴趣的变体。
ELF 格式本身是一个漫长而棘手的技术阅读,是必需的
精确区分变体的背景。简介:一个ELF文件
包含一个 ELF header 结构,其中一个字段包含 type-identifier
文件作为目标文件、共享库或程序。当文件是
程序或共享库,它还包含一个可选的 程序头 table
structure 其字段提供 运行time linker/loader 参数
它需要在一个过程中加载文件。在ELF结构方面,
程序和共享库之间的区别很小:它是
对他们的行为产生影响的详细内容
从装载机中引出。
对于冗长而棘手的技术阅读,请尝试 Excutable and Linkable Format (ELF)
我知道有很多关于共享库和静态库的用例的问题,这个问题不是关于那个的。我问的是存储在磁盘上的文件格式的差异。
为什么问题是,两者之间有什么区别?还是完全一样,只是用法不同?
我相信它们是不一样的,因为共享库上的 运行 'nm' 需要 -D 标志。显然,它需要做一些不同的事情。为什么?
它们都是ELF文件吗?
唯一的区别是共享库可以包含一些依赖路径吗?
静态库只不过是 relocatable 对象的集合(它甚至不是 ELF,而是 ELF 的虚拟存档)。
共享库是一个独立的功能块,具有定义的接口(即符号 table)和依赖项(它是一个 ELF 文件)。
来源
我在示例中使用的源代码如下:
class T {
public:
T(int _x) : x(_x) { }
T& operator=(const T& rhs) { x = rhs.x; return *this; }
int getX() const { return x; }
private:
int x = 0;
};
正在创建共享库
$ g++ -shared -fPIC -c test.cpp -o test.out && ld -o libtest.so test.out
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078
正在创建静态库
$ g++ -fPIC -c test.cpp -o test.out && ar rcs libtest.a test.out
都是ELF文件吗?
有点...这是共享库的 readelf -h
的输出:
$ readelf -h libtest.so
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400078
Start of program headers: 64 (bytes into file)
Start of section headers: 408 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 1
Size of section headers: 64 (bytes)
Number of section headers: 5
Section header string table index: 2
静态库输出很相似,但不完全相同:
$ readelf -h libtest.a
File: libtest.a(test.out)
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 360 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 9
Section header string table index: 6
首先跳出的是静态库中的File
入口。它不是 ELF 对象,而是 包含 ELF 对象。确认这一点的另一种方法是查看带有 hexdump -C
(截断)的文件。一、共享库:
$ hexdump -C libtest.so
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 3e 00 01 00 00 00 78 00 40 00 00 00 00 00 |..>.....x.@.....|
00000020 40 00 00 00 00 00 00 00 98 01 00 00 00 00 00 00 |@...............|
00000030 00 00 00 00 40 00 38 00 01 00 40 00 05 00 02 00 |....@.8...@.....|
00000040 51 e5 74 64 06 00 00 00 00 00 00 00 00 00 00 00 |Q.td............|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000070 10 00 00 00 00 00 00 00 47 43 43 3a 20 28 47 4e |........GCC: (GN|
我们可以在这里非常清楚地看到字符序列 ELF
,就在文件的开头。这是静态库输出:
$ hexdump -C libtest.a
00000000 21 3c 61 72 63 68 3e 0a 2f 20 20 20 20 20 20 20 |!<arch>./ |
00000010 20 20 20 20 20 20 20 20 31 34 38 35 34 36 31 31 | 14854611|
00000020 36 36 20 20 30 20 20 20 20 20 30 20 20 20 20 20 |66 0 0 |
00000030 30 20 20 20 20 20 20 20 34 20 20 20 20 20 20 20 |0 4 |
00000040 20 20 60 0a 00 00 00 00 74 65 73 74 2e 6f 75 74 | `.....test.out|
00000050 2f 20 20 20 20 20 20 20 31 34 38 35 34 36 31 31 |/ 14854611|
00000060 36 36 20 20 31 30 30 30 20 20 31 30 30 30 20 20 |66 1000 1000 |
00000070 31 30 30 36 36 34 20 20 39 33 36 20 20 20 20 20 |100664 936 |
00000080 20 20 60 0a 7f 45 4c 46 02 01 01 00 00 00 00 00 | `..ELF........|
00000090 00 00 00 00 01 00 3e 00 01 00 00 00 00 00 00 00 |......>.........|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 68 01 00 00 |............h...|
000000b0 00 00 00 00 00 00 00 00 40 00 00 00 00 00 40 00 |........@.....@.|
000000c0 09 00 06 00 00 47 43 43 3a 20 28 47 4e 55 29 20 |.....GCC: (GNU)
我们可以在 ELF 头开始之前看到一堆额外的东西,证实了我们的假设,即静态库与共享库的存储方式不同。
另一个区别是 Type
条目;共享库被标记为可执行,而静态库则不是。事实上,共享库和可执行文件之间根本没有太大区别:https://askubuntu.com/questions/690631/executables-vs-shared-objects
静态库,例如libfoo.a
不是任何类型的 executable。
它只是 unix ar
format 中的索引存档
恰好是 ELF 的其他文件
目标文件。
像任何存档一样创建静态库:
ar crs libfoo.a objfile0.o objfile1.0...objfileN.o
输出新存档(c
)libfoo.a,插入目标文件(r
)
并添加了索引 (s
).
您会在程序中听到 linking libfoo.a
。这并不意味着
libfoo.a
本身 被 link 编入程序或与程序一起编入。这意味着 libfoo.a
作为存档传递给 linker,它可以从中提取并 link
该程序只是程序需要的存档中的那些目标文件。
所以静态库的格式(ar
格式)只是一个object-file
linker 输入的捆绑格式:它同样可以是其他一些捆绑
格式对 linker 的任务没有任何影响,即消化一组
目标文件和共享库并生成程序或共享库,
从他们。 ar
格式是历史的选择。
另一方面,共享库,例如libfoo.so
、是一个ELF文件
而不是任何类型的存档。
不要怀疑静态库是一种 ELF 文件
事实上,所有 well-known ELF-parsers - objdump
、readelf
、nm
-
将解析一个静态库。这些工具都知道静态库是
个 ELF 对象文件的存档,因此它们只解析所有对象文件
在库中,就像您在命令行中列出它们一样。
将 -D
选项与 nm
一起使用只是指示工具 select
只有动态交易品种 table(s) 中的交易品种,如果有的话,
它解析的 ELF 文件的数量 - 运行时间 linker 可见的符号
- 无论它们是否从存档中解析。它是
与 objdump -T
和 readelf --dyn-syms
相同。 不是
必须使用这些选项来解析共享库中的符号。如果
如果您不这样做,那么默认情况下您只会看到 完整 符号 table。
如果您 运行 nm -D
在静态库上,您将被告知 no symbols
,因为
存档中的每个目标文件 - 同样,如果您 运行 nm -D
每个
这些目标文件单独。原因是目标文件
没有动态符号 table:只有共享库或程序有一个。
目标文件、共享库和程序都是ELF格式的变体。 如果您对 ELF 变体感兴趣,这些是您感兴趣的变体。
ELF 格式本身是一个漫长而棘手的技术阅读,是必需的 精确区分变体的背景。简介:一个ELF文件 包含一个 ELF header 结构,其中一个字段包含 type-identifier 文件作为目标文件、共享库或程序。当文件是 程序或共享库,它还包含一个可选的 程序头 table structure 其字段提供 运行time linker/loader 参数 它需要在一个过程中加载文件。在ELF结构方面, 程序和共享库之间的区别很小:它是 对他们的行为产生影响的详细内容 从装载机中引出。
对于冗长而棘手的技术阅读,请尝试 Excutable and Linkable Format (ELF)