dlopen da memory?

Eu estou procurando uma maneira de carregar o código do object gerado diretamente da memory.

Eu entendo que, se eu gravá-lo em um arquivo, posso chamar o dlopen para carregar dinamicamente seus símbolos e vinculá-los. No entanto, isso parece um pouco indireto, considerando que ele começa na memory, é gravado em disco e, em seguida, é recarregado na memory por dlopen. Eu estou querendo saber se há alguma maneira de vincular dinamicamente o código de object que existe na memory. Pelo que posso dizer, pode haver algumas maneiras diferentes de fazer isso:

  1. O truque começa a pensar que a localização da sua memory é um arquivo, mesmo que nunca deixe memory.

  2. Encontre alguma outra chamada de sistema que faça o que estou procurando (não acho que isso exista).

  3. Encontre alguma biblioteca de vinculação dinâmica que possa vincular o código diretamente na memory. Obviamente, este é um pouco difícil para o google, como “biblioteca de vinculação dinâmica” acende informações sobre como vincular bibliotecas dinamicamente, não em bibliotecas que executam a tarefa de vincular dinamicamente.

  4. Resumo alguma API de um vinculador e criar uma nova biblioteca para fora sua base de código. (obviamente esta é a opção menos desejável para mim).

Então, quais destes são possíveis? factível? Você poderia me indicar algumas das coisas que eu supus que existiam? Existe outra maneira que eu nem sequer pensei?

Não há uma maneira padrão de fazer isso além de escrever o arquivo e, em seguida, carregá-lo novamente com dlopen() .

Você pode encontrar algum método alternativo em sua plataforma específica atual. Cabe a você decidir se isso é melhor do que usar a abordagem ‘padrão e (relativamente) portátil’.

Como gerar o código do object em primeiro lugar é específico da plataforma, técnicas adicionais específicas da plataforma podem não ser importantes para você. Mas é um julgamento – e, de qualquer modo, depende de uma técnica não padronizada, que é relativamente improvável.

Não vejo por que você consideraria o dlopen , pois isso exigirá muito mais código não-portável para gerar o formato de object correto no disco (por exemplo, ELF) para carregamento. Se você já sabe como gerar código de máquina para sua arquitetura, apenas a memory mmap com PROT_READ|PROT_WRITE|PROT_EXEC e coloque seu código lá, então atribua o endereço a um ponteiro de function e chame-o. Muito simples.

Eu precisava de uma solução para isso porque eu tenho um sistema com script que não tem sistema de arquivos (usando blobs de um database) e precisa carregar plug-ins binários para suportar alguns scripts. Esta é a solução que eu desenvolvi, que funciona no FreeBSD, mas pode não ser portátil.

 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; } 

Obviamente, o código não possui nenhum tipo de verificação de erros, etc., mas essa é a principal funcionalidade.

ETA: Minha suposição inicial de que fdlopen é POSIX estava errada, isso parece ser um FreeBSD-ism.

Você não precisa carregar o código gerado na memory, pois já está na memory!

No entanto, você pode, de uma maneira não portátil, gerar código de máquina na memory (desde que esteja em um segmento de memory mmap -ed com o sinalizador PROT_EXEC ).

(nesse caso, nenhuma etapa de “vinculação” ou de relocação é necessária, pois você gera código de máquina com endereços absolutos ou relativos definitivos, em particular para chamar funções externas)

Existem algumas bibliotecas que fazem isso: No GNU / Linux em x86 ou x86-64 , eu conheço o GNU Lightning (que gera rapidamente código de máquina que corre lentamente), DotGNU LibJIT (que gera código de qualidade média) e LLVM & GCCJIT (que é capaz de gerar código bastante otimizado na memory, mas leva tempo para emiti-lo). E o LuaJit também tem alguma facilidade similar. Desde 2015, o GCC 5 tem uma biblioteca gccjit .

E, claro, você ainda pode gerar código C em um arquivo, separar um compilador para compilá-lo em um object compartilhado e dlopen esse arquivo de object compartilhado. Eu estou fazendo isso no GCC MELT , uma linguagem específica do domínio para estender o GCC. Funciona muito bem na prática.

adenda

Se o desempenho de escrever o arquivo C gerado for uma preocupação (não deveria ser, já que compilar um arquivo C é muito mais lento do que escrevê-lo) considere usar algum sistema de arquivos tmpfs para isso (talvez em /tmp/ que é frequentemente um sistema de arquivos tmpfs Linux)