As bibliotecas compartilhadas são carregadas no início da execução de um programa. No Linux, o dynamic loader procura pelas bibliotecas em /lib e /usr/lib. Caso a biblioteca não esteja presente neste caminho, recebemos uma mensagem de erro parecida com a mensagem a seguir:
error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
Imagine um ambiente de desenvolvimento, onde estamos codificando uma biblioteca. Não queremos instalar esta biblioteca no sistema só para testá-la. Uma alternativa é configurar a variável de ambiente LD_LIBRARY_PATH, apontando para o diretório onde se encontra o binário da biblioteca. Assim o dynamic loader vai procurar pela biblioteca também neste diretório.
$ export LD_LIBRARY_PATH=/home/user/libfoo/
Uma segunda opção seria no momento em que seu programa é “linkado”, passar o caminho da biblioteca para a opção -rpath do linker. Isto coloca o caminho de busca pela biblioteca dentro da estrutura do executável (ELF). A opção -Wl do gcc serve para passar parâmetros para o linker (usando “,” no lugar de espaço) que é chamado automaticamente após a compilação.
$ gcc -shared -Wall -o libfoo.so foo.c
$ gcc -Wall -o test test.c -L/home/user/libfoo/ -lfoo
$ ./test # Erro! Não acha a biblioteca libfoo.so
$ gcc -Wall -Wl,-rpath,/home/user/libfoo/ -o test test.c \ -L/home/user/libfoo/ -lfoo
$ ./test # Funciona!
Olá!
Não somente configurar a variável LD_LIBRARY_PATH para o diretório onde está explicitamente a biblioteca como também para o diretório corrente!
export LD_LIBRARY_PATH=”.”
ou
export LD_LIBRARY_PATH=”.:${LD_LIBRARY_PATH}”
[]s
Faz tempo que não faço isso, mas acho que
$ LD_PRELOAD= ./test
funcionaria.
ops. O sanitize comeu parte do meu comentário. seria
$ LD_PRELOAD=<caminho para o .so> ./test
Cássio, acho que não!
Para esquema do uso da LD_PRELOAD e preciso que seu objeto tenha declarações explicitas do tipo “constructor”, exemplo abaixo!
## wrap.c:
#define _GNU_SOURCE
#include
#include
static void wrap_init(void) __attribute__((constructor));
static FILE *(*s_fopen)(const char *, const char *);
FILE *fopen(const char *path, const char *mode)
{
printf(“Olá, wrapper para fopen: %p\n”, s_fopen);
if(!s_fopen) {
printf(“Ops, endereço NULL\n”);
return NULL;
}
return s_fopen(path, mode);
}
static void wrap_init(void)
{
s_fopen = dlsym(RTLD_NEXT, “fopen”);
printf(“Init: %p\n”, s_fopen);
}
## End wrap.c
## lib.c
#include
static void lib_init(void) __attribute__((constructor));
static void lib_init(void) {
fopen(“foo.txt”, “r”);
}
## End lib.c
# Compila ele como shared
# gcc -shared -o libninja-wrapper.so wrapper.c lib.c
Dai o seu programa que por exemplo venha a chamar a função fopen() e por sua vez utiliza o LD_PRELOAD, dai será possível fazer um “catch” da função!
# LD_PRELOAD=./libninja-wrapper.so ./seu-programa-que-dentr-chama-fopen
Abraços!
[]s
Ops, a lista de libs compartilhadas também pode ser mantida no arquivo /etc/ld.so.conf, não?
@Andre: Sim, desde que o cache esteja atualizado atraves do comando ldconfig
Só uma coisa que sempre atrapalha, lembre-se que se o seu programa tem que rodar com suid o LD_LIBRARY_PATH e outras variaveis de ambiente LD_* são ignoradas, por medidas de segurança. Por isso a unica solução neste caso é usar o run_path.