我想要一个小型的"应用程序加载器"程序,该程序通过TCP从外部服务器接收其他二进制应用程序文件并运行它们。
我可以通过将传输的文件保存到硬盘并使用 system(( 调用来运行它来做到这一点。 但是,我想知道是否可以在不接触硬盘驱动器的情况下从内存启动新应用程序。
加载新应用程序后,加载程序应用程序的状态无关紧要。 我更喜欢坚持使用C,但也欢迎C++解决方案。 如果可能的话,我还想坚持使用标准的 Linux C 函数,不使用任何外部库。
简短回答:不。
长答案:这是可能的,但很难做到这一点,而不将其写到磁盘。理论上你可以编写自己的elf加载器来读取二进制文件,映射一些内存,根据需要处理动态链接,然后转移控制权,但这是非常多的工作,几乎不值得付出努力。
下一个最佳解决方案是将其写入磁盘并尽快调用取消链接。磁盘甚至不必是"真正的"磁盘,它可以是tmpfs或类似磁盘。
我最近一直在使用的替代方法是不传递完整的编译二进制文件,而是传递 LLVM 字节码,然后可以根据需要进行 JIT/解释/保存。这也具有使应用程序在异构环境中工作的优点。
尝试fmemopen
、fileno
和fexecve
的组合可能很诱人,但这行不通,原因有两个:
-
从
fexecve()
手册页:"文件描述符 fd 必须以只读方式打开,并且调用方必须具有执行它引用的文件的权限">
即它需要是一个引用文件的 fd。
-
从
fmemopen()
手册页:"没有与这些函数返回的文件流关联的文件描述符(即,如果在返回的流上调用
fileno(3)
将返回错误(">
比这样做容易得多的是 C 只需设置 tmpfs 文件系统。您将拥有硬盘接口的所有优势,从您的程序/服务器/您可以做exec
的任何事情。这些类型的虚拟文件系统现在非常有效,页面缓存中实际上只有一个可执行文件副本。
正如 Andy 指出的那样,为了使这种方案高效,您必须确保不使用缓冲写入文件,而是直接"写入"(在更广泛的意义上(。
- 你必须知道你的可执行文件会有多大
- 在 TMPFS 上创建一个文件
- 使用
ftruncate
将其缩放到该大小 - 使用
mmap
将该文件"映射"到内存中,以获取缓冲区的地址 - 将该地址直接传递给
recv
调用以就地写入数据 -
munmap
文件 - 使用文件调用
exec
-
rm
文件。 即使可执行文件仍在运行时也可以完成
您可能需要查看并重用 UPX,它将可执行文件解压缩到内存,然后将控制权转移到 ld-linux
以启动它。