您在这里看到的是动态加载程序打开并读取所需库的标题。几乎所有 ELF 程序的 strace(这是 Linux 中的标准可执行格式)都以一堆 open/read/mmap/close 开头,原因是:动态加载器正在加载所需的图书馆。
你在这里看到的:
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\273\0\0\0\0\0\0"..., 832) = 832
这正是加载器从文件中读取的内容:
-
3:这是由open() 分配给打开文件的fd。
-
"\177ELF\2\1\1\0...":这是正在读取的文件的内容。数字在那里是因为它们是八进制转义序列,例如\1 表示字节 1。它们是这样打印的,因为否则您将无法看到它们,并且会在您的终端上造成混乱,因为其中大多数是特殊的不可打印字符。
-
832:这是加载程序要从文件中读取的字节数。
-
= 832:这是read() 的结果,表示所有请求的字节都已读取。
换句话说,这些转义序列只是一种使不可打印字节可读的方法。你可以在加载器试图打开的文件上测试这个运行od -bc,你可以看到它的八进制形式的内容加上可打印的字符和反斜杠转义:
$ od -bc /lib/x86_64-linux-gnu/libc.so.6 | head -n4
0000000 177 105 114 106 002 001 001 003 000 000 000 000 000 000 000 000
177 E L F 002 001 001 003 \0 \0 \0 \0 \0 \0 \0 \0
0000020 003 000 076 000 001 000 000 000 260 034 002 000 000 000 000 000
003 \0 > \0 001 \0 \0 \0 260 034 002 \0 \0 \0 \0 \0
更完整的示例如下,来自strace /bin/true:
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 4
read(4, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\4\2\0\0\0\0\0"..., 832) = 832
fstat(4, {st_mode=S_IFREG|0755, st_size=1689360, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0d3d877000
mmap(NULL, 3795296, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x7f0d3d2dd000
mprotect(0x7f0d3d472000, 2097152, PROT_NONE) = 0
mmap(0x7f0d3d672000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x195000) = 0x7f0d3d672000
mmap(0x7f0d3d678000, 14688, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f0d3d678000
close(4)
您可以看到加载程序正在打开“libc”,这是标准 C 库的 ELF 文件。它读取其标题以确定要加载哪些部分,然后mmaps 内存中所有需要的部分,分配正确的权限。