strace记录的Linux read系统调用-如何理解指向缓冲区值的指针?

3

我运行了strace,在输出中得到类似以下的行:

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

我已经阅读了关于read的文档,所以字符串""是指向缓冲区的指针(ssize_t read(int fd, void *buf, size_t count);),但是这个特定的字符串是什么意思呢? 特别地:

  • ELF 很可能是可执行链接文件 - 为什么在这里使用指针?
  • \ 让特殊字符转义 - 为什么在这里转义数字?
  • > 它是用来做什么的?

2
这是从读取的数据。转义值以八进制表示。 - Hasturkun
@Hasturkun,我在 man strace 中发现"字符指针被解引用为C字符串",这是我现在通过搜索 read 所能找到的所有信息。请问您是否可以发布一个链接/指针,让我可以进一步了解此问题? - Marisha
1
你正在读取的文件是什么格式?查一下看看那些字节代表什么。 - Shawn
执行文件格式(Executable and Linkable Format)是一种常用于可执行文件、目标代码和共享库的标准文件格式。它包含了一个文件头,用于描述该文件及其相关信息。 - Shawn
1
八进制是许多工具在打印非ASCII字节时的默认选项。可能有一个选项可以改用十六进制。 - Shawn
显示剩余3条评论
1个回答

7
您在这里看到的是动态加载器打开并读取所需库的头文件。几乎所有 ELF 程序(这是 Linux 中的标准可执行格式)的 strace 都以大量的 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文件。它读取其头文件以确定要加载哪些部分,然后将所有所需的部分映射到内存中,并分配正确的权限。

谢谢。我阅读strace输出时有一个相关的问题:为什么所有这些0x7f0d3d672000都不同?为什么下一行不使用前一行的输出?我猜应用程序在其中进行了一些计算,但可能还有其他原因。 - Marisha
@Marisha 是的,那正是原因所在。动态加载器会进行必要的计算,以确定各个部分需要在内存中加载的确切位置。由于系统启用了地址空间布局随机化(ASLR),这些数字可能看起来是随机的。 - Marco Bonelli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接