来源
我在示例中使用的源代码如下:
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