从内存中删除?

我正在寻找一种方法来直接从内存中加载生成的对象代码。

我明白,如果我把它写到一个文件中,我可以调用dlopendynamic加载它的符号并链接它们。 然而,这看起来有点迂回,考虑到它在内存中启动,写入磁盘,然后通过dlopen重新加载到内存中。 我想知道是否有一些方法来dynamic链接目标代码存在于内存中。 从我可以告诉的可能有几种不同的方式来做到这一点:

  1. 把它想成你的内存位置是一个文件,尽pipe它永远不会留下内存。

  2. find一些其他的系统调用,我正在寻找(我不认为这存在)。

  3. find一些可以直接在内存中链接代码的dynamic链接库。 很明显,这对于google来说有点难,因为“dynamic链接库”提供了关于如何dynamic链接库的信息,而不是dynamic链接任务的库。

  4. 从链接器中抽取一些API,并从其代码库中创build一个新的库。 (显然这对我来说是最不可取的select)。

那么哪些是可能的? 可行? 你能指出我所假设的任何东西吗? 还有没有想过的另一种方式?

除了写出文件,然后用dlopen()重新加载之外,没有其他的标准方法。

您可能会在当前的特定平台上find一些替代方法。 这取决于你是否比使用“标准和(相对)便携”方法更好。

由于首先生成目标代码是特定于平台的,所以额外的特定于平台的技术可能对您无关紧要。 但是,这是一个判断的呼声 – 无论如何都取决于是否存在相对不可能的非标准技术。

我不明白为什么你会考虑dlopen ,因为这将需要更多的非便携代码来生成磁盘上正确的对象格式(如ELF)加载。 如果您已经知道如何为您的架构生成机器代码,只需使用PROT_READ|PROT_WRITE|PROT_EXEC内存PROT_READ|PROT_WRITE|PROT_EXEC到您的代码,然后将该地址分配给函数指针并调用它。 很简单。

我需要一个解决scheme,因为我有一个没有文件系统的脚本系统(使用数据库中的blob),需要加载二进制插件来支持一些脚本。 这是我提出的在FreeBSD上工作的解决scheme,但可能不是可移植的。

 void *dlblob(const void *blob, size_t len) { /* Create shared-memory file descriptor */ int fd = shm_open(SHM_ANON, O_RDWR, 0); ftruncate(fd, len); /* MemMap file descriptor, and load data */ void *mem = mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0); memcpy(mem, blob, len); munmap(mem, len); /* Open Dynamic Library from SHM file descriptor */ void *so = fdlopen(fd,RTLD_LAZY); close(fd); return so; } 

代码显然没有任何错误检查等,但这是核心function。

ETA:我最初假设fdlopen是POSIX是错误的,这似乎是一个FreeBSD-ism。

你不需要加载在内存中生成的代码,因为它已经在内存中!

但是,您可以用一种不可移植的方式在内存中生成机器代码(只要它位于使用PROT_EXEC标志的mmap内存段中)。

(在这种情况下,不需要“链接”或重定位步骤,因为您生成的机器代码具有明确的绝对或相对地址,尤其是调用外部函数)

有些库是这样做的:在x86x86-64下的GNU / Linux上,我知道GNU Lightning (可以快速生成机器码), DotGNU LibJIT (生成中等质量代码)和LLVM & GCCJIT能够在内存中生成相当优化的代码,但需要时间来发出它)。 LuaJit也有类似的设施。 自2015年以来,GCC 5拥有一个gccjit库。

当然,您仍然可以在文件中生成C代码,派生一个编译器将其编译到共享对象中,然后将该共享对象文件删除。 我在GCC MELT中这样做,这是一种扩展GCC的领域特定语言。 它在实践中工作得很好。

附加物

如果编写生成的C文件的性能是一个问题(不应该,因为编译C文件比编写C文件慢得多)考虑使用一些tmpfs文件系统(可能在/tmp/ ,通常是一个tmpfs文件系统Linux的)