使用objcopy工具可以轻松地将任意文件嵌入到ELF可执行文件中:

objcopy --add-section program.file1=file1.dat \
        --add-section program.file2=file2.dat \
        program program+files

在我看来,program+files应该可以在不打开和读取任何外部文件的情况下以编程方式访问file1file2.然而,似乎没有一种简单的方法可以从运行的程序中获取这些信息.

这些文件被添加为ELF可执行文件的命名部分.然而,Linux只加载ELF程序头表所描述的段.这些部分永远不会出现在该集合中,因为它们不是执行所必需的.

因此,虽然可以获得指向当前运行的程序的ELF标头的指针,但这是没有意义的,因为根本没有加载这些节.

uintptr_t address = getauxval(AT_PHDR) & -4096;
Elf64_Ehdr *elf = (Elf64_Ehdr *) address;

// dangling pointer, sections aren't loaded by the OS
Elf64_Shdr *sections = ((unsigned char *) elf) + elf->e_shoff;

我的目的是在运行时按名称搜索节,找到以program.为前缀的节,并计算指向它们的指针,以便我的代码可以像使用普通内存块一样使用它们.

我不能为此使用预定义的符号,因为我想支持任意数量的嵌入文件,包括根本没有嵌入文件.我需要在运行时查找这些部分.

Linux将只加载标记为PT_LOAD的段.这些部分可以以某种方式放置在PT_LOAD个片段中吗?objcopy似乎没有能力编辑节目头表和添加新的PT_LOAD段.你要怎么做?

推荐答案

我的目的是在运行时按名称搜索节,找到以PROGRAM为前缀的节.并计算指向它们的指针,以便我的代码可以像使用普通内存块一样使用它们.

您可以在磁盘上找到program(使用/proc/self/exe)、mmapit1、解码区段标头(参见this answer),然后计算指向感兴趣区段的指针并根据需要使用它们.

这些段能以某种方式放在PT_LOAD段中吗?

否:这将需要重建可执行文件的某些部分,而这些部分在不重新链接整个程序的情况下是无法重建的.

Update:

如果您不太关心程序的内存使用情况,可以修改最后LOAD个段以"覆盖"entireprogram+files段,然后可以跳过单独的mmap段--文件可能已经在内存中了.

你只需要增加.p_filesz.p_memsz,这样phdr.p_offset + phdr.p_filesz == file_size就可以了.

代价是您将导致通常不会加载到内存中的数据(例如段标题、调试段(如果有的话))占用内存.但是对于请求分页,代价可能非常小--不应该访问这些"额外的"内存区域,因此不应该导致它们被分页.

另外,我知道没有标准的实用程序可以更新.p_filesz等,但在CPython中编写这样的补丁程序非常容易.


1您不必对整个program进行mmap,只需对包含所需部分的部分进行mmap即可.

C++相关问答推荐

海湾合作委员会是否保证大小匹配的访问?

字符数组,字符指针,在一种情况下工作,但在另一种情况下不工作?

sizeof结果是否依赖于字符串的声明?

如何将不同长度的位转换成字节数组?

我编译了一个新的c程序,并收到以下错误

为什么在C中进行大量的位移位?

GCC预处理宏和#杂注GCC展开

如何使用[BTStack]BLE发送大型(>;2kb)信息包

C语言中的外部关键字

For循环不会迭代所有字符串字符吗?(初学者问题)

为什么Linux无法映射这个PT_LOAD ELF段?

将 struct 数组写入二进制文件时发生Valgrind错误

在运行时判断C/C++指针是否指向只读内存(在Linux操作系统中)

使用C++中的字符串初始化 struct 时,从‘char*’初始化‘char’使指针变为整数,而不进行强制转换

为什么我无法访问C语言中的文件

如何组合两个宏来初始化C语言中的字符串数组?

是否有单独的缓冲区用于读写库调用?

按字典顺序打印具有给定字符的所有可能字符串

无法将字符串文字分配给 C 中的字符数组

既然我们在 if 中将 int 的值更改为 10,为什么在第二个 fork 后,子进程及其创建的子进程都会打印 33 ?