Como sabemos, qualquer arquivo executável, que esteja em execução, é carregado na RAM.
Além disso, temos dois tipos de bibliotecas: biblioteca de links estáticos e biblioteca de links dinâmicos.
Os dois tipos de bibliotecas também devem ser carregados na RAM enquanto são necessários.
Como eu sei, temos duas maneiras de carregar a biblioteca dinâmica:
- vinculá-lo durante a compilação, como
g++ -lsofile
- carregar dinamicamente no código, temos
dlopen
que fazer isso
Postei esta pergunta , mas ainda não posso ter certeza de que poderíamos listar todos os arquivos lib. Para o primeiro caso acima, acho que podemos obter o arquivo de link com ldd
, ou verificar /proc/{PID}/maps
. Mas para o segundo caso, estou pensando se consigo pegar os arquivos de link com algum método, segue um exemplo:
void SomeModule()
{
//dlopen here to link mysofile
}
int main()
{
if (user_enter == 'a')
{
printf("hello world");
}
else
{
SomeModule();
}
}
Neste exemplo, quando o executarmos e digitarmos always a
, o dlopen
nunca será chamado, portanto mysofile
nunca será vinculado, ou seja mysofile
, nunca será carregado na RAM. Estou certo?
Em caso afirmativo, como posso obter os arquivos lib necessários do arquivo executável, exceto lendo o código-fonte?
Errado !
um arquivo executável é mapeado no espaço de endereço virtual dos processos que o executam, pelo subsistema de memória virtual do kernel. A RAM física é gerenciada apenas pelo kernel. Leia Sistemas Operacionais: Três Peças Fáceis para saber mais.
Nem todo o segmento de código desse arquivo executável é paginado (não carregado!) na RAM. Em particular, um grande trecho de código que nunca é usado (por exemplo, porque contém alguma função grande que nunca é chamada) não irá para a RAM. Leia sobre paginação e cache de página .
Às vezes, não há RAM física suficiente para lidar convenientemente com todas as páginas necessárias. Nessa situação, você observa uma surra .
o vinculador dinâmico (consulte ld-linux(8) ) e também dlopen(3) usa mmap(2) para mapear a memória de alguns segmentos da biblioteca compartilhada. Portanto, não carrega todo o segmento de código do plug-in na RAM. Leia também o artigo Como escrever bibliotecas compartilhadas de Drepper .
Em geral, não há absolutamente nenhuma maneira de prever quais futuras bibliotecas compartilhadas seriam usadas e
dlopen
editadas. Pense nos dois cenários a seguir:um programa de longa duração (talvez o seu navegador) pede ao usuário para obter alguma biblioteca compartilhada (talvez baixando-a da rede) e depois
dlopen
.um processo está gerando algum código C em um arquivo temporário
/tmp/emittedcode.c
, compile (aofork
executar um processo apropriado executando algunsgcc -O -Wall -fPIC /tmp/emittedcode.c -shared -o /tmp/emittedcode.so
) esse arquivo em um plug-in temporário/tmp/emittedcode.so
edlopen
-s esse plug-in temporário (é claro que depoisdlsym
-ing símbolos apropriados lá).Eu gosto bastante da segunda abordagem. Observe que compilar para C é um hábito bem estabelecido. E os compiladores atuais são rápidos o suficiente para permitir fazer isso em alguma interação REPL.
BTW, em um desktop Linux, um processo pode ter
dlopen
muitos objetos compartilhados, ou seja, plugins (pelo menos centenas de milhares e provavelmente milhões). Veja meumanydl.c
exemplo (que gera código C "aleatório" em arquivos temporários e repita).PS. Esteja ciente também do Halting Problem , relacionado à impossibilidade teórica de prever todos os
dlopen
caminhos futuros.Você está certo, se
dlopen
nunca for chamado, a biblioteca de destino nunca será carregada na memória (do processo).Determinar as bibliotecas necessárias sem ler o código-fonte parece uma variante do problema da parada. Você pode usar algumas heurísticas: se o programa não estiver vinculado a
libdl
, ele não poderá usardlopen
; em caso afirmativo, você pode usarstrace
(consulte Como descobrir as cargas executáveis das bibliotecas dinâmicas quando executadas? ) Ou tentar descobrir os argumentos paradlopen
usar a análise estática. Mas o programa pode incluirlibdl
diretamente (por meio de links estáticos ou construindo o código); e como o vinculador dinâmico não é mágico, não há nada que impeça um programa de reimplementá-lo sozinho, então você não pode ser absolutamentecertifique-se de ter capturado todas as bibliotecas necessárias usando essas heurísticas. Talvez existam programas que descobrem que estão sendo rastreados e pulam o carregamento da biblioteca ...A única maneira segura de listar todas as bibliotecas necessárias é ler o código-fonte.