从内存加载.so文件

6

可能是重复问题:
从内存中加载dlopen?

我已经看到了Windows的DLL文件,可以从内存缓冲区加载,但我在Linux上找不到它的任何地方,“ld”源代码是我见过的最复杂的代码。所以:

有没有加载.so文件的内存示例? 即使是简单的一个也可以,我只是不知道从哪里开始,即使我已经阅读了大部分ELF规范,它对我来说仍然神秘。


.so文件通过套接字连接发送,我正在寻找解决方案,而不是替代方案。 - killercode
@killercode,你正在寻找一个解决方案来解决一个你定义得非常狭窄的问题。你目前缺乏从内存中编写.so文件的知识,并希望支付他人来完成这项任务。除非你能为我们提供一些上下文,否则其他替代方案更有意义。 - Dan Fego
正在通过套接字发送 .so 文件,我不想将其写入磁盘,因为我的应用程序可能没有将文件写入磁盘的特权,所以我想从内存中运行它,在任何平台上避免这些问题,而不仅仅是在 Linux 上。 - killercode
杀手代码...你找到答案了吗?你有一些代码可以展示吗? - Morteza Milani
3个回答

8
您正在查看错误的源代码:ld不执行程序和库加载。相反,您应该查看libc中找到的dlopendlsym函数的源代码。此外,您应该查看动态链接器的源代码:ld-linux.so(真实名称因平台而异;执行ldd /bin/ls以查找动态链接器所在位置)。
ELF解析并不困难,但需要注意细节,并理解特定CPU的汇编代码;您还需要平台的ABI规范(32位和64位Linux不同,并且在不同的CPU之间也不同)。
如果您只需要在运行时从内存加载对象文件(即,它不必是SO),则可以查看X11项目:他们已经实现了一个模块系统,基本上在某个地址加载对象代码并重定位它。

-1
你需要使用dlopen()函数族(在GNU/Linux中,它们定义在/usr/include/dlfcn.h中)。
例如,可以参考PHP如何处理模块

1
我知道如何从磁盘使用.so文件,但我想从内存中使用它们,因为它们在磁盘上不存在。 - killercode

-1

对于你来说,“从内存中加载.so文件”是什么意思?

如果您有任何*.so文件,那么它在某个文件系统中并且有一个路径。然后只需在其上使用dlopen

如果它不是一个文件,那它是什么?您是如何将其存储到内存中的?您确切地拥有什么在内存中?(在内存中是否有ELF头和ELF布局?)

如果您有足够的信息来生成ELF *.so文件,请将此类文件转储(即写入)到某个文件系统中(如果您关心磁盘性能,请使用临时文件系统,如tmpfs)。 然后在其上使用dlopen

如果你没有足够的信息来制作一个 ELF .so 文件,那么你很可能是在内存中动态构建代码。看看现有的机器代码生成基础设施(如 LLVM, GCCJIT, libjit, GNU lightning, LuaJit ....)在做什么。

如果你在内存中有完整的功能代码,请确保该内存使用mmapmprotect可执行,并跳转到它(例如使用函数指针技巧)。


我对负面反馈感到相当惊讶。我说错了什么?为什么我的回答不相关? - Basile Starynkevitch
虽然并没有完全回答他似乎固执地想要实现的方式,但这些信息通常是有用的。+1 - Dan Fego
我不太明白原帖作者所说的"从内存中加载.so文件"(或者说从内存中加载任何类型的文件)的确切含义,因为文件只能从文件系统中读取。我猜测在Windows上有这样的函数是因为(如果我没记错的话)在Windows上有几个进程不能同时对一个文件进行操作(例如,在Windows上无法删除另一个进程打开的文件,但在Linux上可以这样做)。 - Basile Starynkevitch
4
他计划通过套接字传递一个 .so 文件,以便将整个文件的内容保存在内存中,并希望从内存中 dlopen() 文件,而不是从磁盘上加载。注意不改变原意,简化表达。 - Dan Fego
原帖没有提到任何类型的套接字或管道。但是,如果他正在从这样一个(不可寻址,不可mmap)的文件描述符中获取.so ELF文件的内容,唯一明智的选择就是将其写入文件,然后使用dlopen打开该文件。 - Basile Starynkevitch

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