【问题标题】:linux read system call produced by strace - how to understand pointer to buffer value?linux读取strace产生的系统调用-如何理解指向缓冲区值的指针?
【发布时间】:2019-09-22 12:02:36
【问题描述】:

我跑了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 上读过man,所以字符串"" 是指向buf (ssize_t read(int fd, void *buf, size_t count);) 的指针,但是那个特定的字符串是什么意思?特别是:

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

【问题讨论】:

  • 这是读取的数据。转义值是八进制的。
  • @Hasturkun,我在man strace 中找到“字符指针被取消引用到C 字符串”,这就是我现在搜索read 所能找到的全部内容。您能否发布一个链接/指针,以便我可以阅读更多内容?
  • 您正在阅读的文件是什么格式的?查一下,看看所有这些字节是什么意思。
  • Base 8 是许多实用程序中打印非 ascii 字节的默认值。可能有一个选项可以使用 base 16。

标签: c pointers file-descriptor strace


【解决方案1】:

您在这里看到的是动态加载程序打开并读取所需库的标题。几乎所有 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 内存中所有需要的部分,分配正确的权限。

【讨论】:

  • 谢谢。我读过strace 输出的一个相关问题:为什么所有这些 0x7f0d3d672000 都不同?为什么下一行不使用前一行的输出?我猜该应用程序会在两者之间进行一些计算,但可能是其他原因。
  • @Marisha 是的,这正是原因。动态加载器执行所需的计算以确定需要将部分加载到内存中的确切位置。这些数字可能看起来是随机的,因为您的系统上启用了ASLR
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-13
  • 2019-11-27
  • 2015-04-15
  • 1970-01-01
  • 2011-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多