linux 读取 strace 生成的系统调用 - 如何理解指向缓冲区值的指针?
linux read system call produced by strace - how to understand pointer to buffer value?
I 运行 strace
并且在它的输出中我得到如下行:
read(3, "7ELF[=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=]>[=11=][=11=][=11=][=11=]3[=11=][=11=][=11=][=11=][=11=][=11=]"..., 832) = 832
我在 read 上读过 man,所以字符串 ""
是指向 buf (ssize_t read(int fd, void *buf, size_t count);
) 的指针,但是那个特定的字符串是什么意思?特别是:
ELF
很可能是可执行文件链接 - 为什么这里是指针?
\
允许转义特殊字符 - 为什么在这里转义数字?
>
有什么用?
您在这里看到的是动态加载程序打开并读取所需库的 header。几乎所有 strace
的 ELF 程序(这是 Linux 中的标准可执行格式)都以一堆 open
/read
/mmap
/close
出于这个原因:动态加载程序正在加载所需的库。
你在这里看到的:
read(3, "7ELF[=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=]>[=10=][=10=][=10=][=10=]3[=10=][=10=][=10=][=10=][=10=][=10=]"..., 832) = 832
加载程序正在从文件中读取的内容:
3
:这是open()
分配给打开文件的fd
。
"7ELF[=21=]..."
:这是正在读取的文件内容。数字在那里是因为它们是八进制转义序列,例如 </code> 表示字节 1。它们是这样打印的,否则你将无法看到它们,并且会在你的终端上造成混乱,因为大多数这些是特殊的不可打印字符。</li>
<li><code>832
:这是加载程序要从文件中读取的字节数。
= 832
:这是read()
的结果,这意味着所有请求的字节都被读取了。
换句话说,那些转义序列只是一种使 non-printable 字节可读的方法。您可以在加载程序试图打开的文件上测试此 运行 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 [=11=] [=11=] [=11=] [=11=] [=11=] [=11=] [=11=] [=11=]
0000020 003 000 076 000 001 000 000 000 260 034 002 000 000 000 000 000
003 [=11=] > [=11=] 001 [=11=] [=11=] [=11=] 260 034 002 [=11=] [=11=] [=11=] [=11=] [=11=]
下面是一个更完整的示例,来自 strace /bin/true
:
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 4
read(4, "7ELF[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]>[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]"..., 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文件。它读取其 header 以确定要加载的部分,然后 mmap
将所有需要的部分存储在内存中,并分配正确的权限。
I 运行 strace
并且在它的输出中我得到如下行:
read(3, "7ELF[=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=]>[=11=][=11=][=11=][=11=]3[=11=][=11=][=11=][=11=][=11=][=11=]"..., 832) = 832
我在 read 上读过 man,所以字符串 ""
是指向 buf (ssize_t read(int fd, void *buf, size_t count);
) 的指针,但是那个特定的字符串是什么意思?特别是:
ELF
很可能是可执行文件链接 - 为什么这里是指针?\
允许转义特殊字符 - 为什么在这里转义数字?>
有什么用?
您在这里看到的是动态加载程序打开并读取所需库的 header。几乎所有 strace
的 ELF 程序(这是 Linux 中的标准可执行格式)都以一堆 open
/read
/mmap
/close
出于这个原因:动态加载程序正在加载所需的库。
你在这里看到的:
read(3, "7ELF[=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=]>[=10=][=10=][=10=][=10=]3[=10=][=10=][=10=][=10=][=10=][=10=]"..., 832) = 832
加载程序正在从文件中读取的内容:
3
:这是open()
分配给打开文件的fd
。"7ELF[=21=]..."
:这是正在读取的文件内容。数字在那里是因为它们是八进制转义序列,例如</code> 表示字节 1。它们是这样打印的,否则你将无法看到它们,并且会在你的终端上造成混乱,因为大多数这些是特殊的不可打印字符。</li> <li><code>832
:这是加载程序要从文件中读取的字节数。= 832
:这是read()
的结果,这意味着所有请求的字节都被读取了。
换句话说,那些转义序列只是一种使 non-printable 字节可读的方法。您可以在加载程序试图打开的文件上测试此 运行 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 [=11=] [=11=] [=11=] [=11=] [=11=] [=11=] [=11=] [=11=]
0000020 003 000 076 000 001 000 000 000 260 034 002 000 000 000 000 000
003 [=11=] > [=11=] 001 [=11=] [=11=] [=11=] 260 034 002 [=11=] [=11=] [=11=] [=11=] [=11=]
下面是一个更完整的示例,来自 strace /bin/true
:
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 4
read(4, "7ELF[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]>[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]"..., 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文件。它读取其 header 以确定要加载的部分,然后 mmap
将所有需要的部分存储在内存中,并分配正确的权限。