dlmopen () не может разрешить определенный символ функции в созданном пространстве имен - PullRequest
1 голос
/ 11 апреля 2020

Я использую dlmopen в C для загрузки общих библиотек в изолированное пространство имен. Моя цель - сделать так, чтобы символы в этом пространстве имен принадлежали загруженным библиотекам. Поэтому они не могут получить доступ к символам в моей основной программе. Текущий - это псевдо-код главной функции, показывающий процесс.

// when first .so is loaded, load it into a new namespace and store that namespace 
// function a() is defined in it
void* handle1 = dlmopen(LM_ID_NEWLM, new_so_name1, RTLD_NOW);
// store the namespace in lmid
dlinfo(handle1,  RTLD_DI_LMID, &lmid); 
// when second .so is loaded, load it in lmid
// function b() is defined in it
void* handle2 = dlmopen(lmid, new_so_name2, RTLD_NOW);

Работает довольно хорошо. И кажется, что и a (), и b () загружаются в пространство имен. Но когда я загружаю третью разделяемую библиотеку, происходит нечто странное:

// If I make a call a() in the third library
void* handle3 = dlmopen(lmid, new_so_name3, RTLD_NOW);
// call a() using dlsym() 

Загрузка успешна, и я могу вызвать эту функцию a (). Но если я сделаю вызов b () в третьей библиотеке и загрузлю его в то же пространство имен:

void* handle3 = dlmopen(lmid, new_so_name3, RTLD_NOW);
printf("error:%s\n", dlerror());

Это выдаст следующую ошибку:

erroe:undefined symbol: b

Похоже, что вторая библиотека не была успешно загружена в пространство имен. Но, как я показал, вторая загрузка прошла успешно, и возвращается ненулевой handle2. Так почему же это происходит, что не так с моим процессом загрузки? Я просто хочу, чтобы все загруженные библиотеки могли совместно использовать символы в этом указанном c пространстве имен, чтобы избежать использования символов в моей основной программе.

РЕДАКТИРОВАТЬ: Приложение

Как предложено @CharlieBurns. Я выкладываю самую маленькую программу ниже, чтобы показать мою проблему.

#define _GNU_SOURCE
#include <stdio.h>
#include <link.h>
#include <dlfcn.h>
void* handle1;
void* handle2;
void* handle3;
Lmid_t lmid;
int main() {
  // handle1 contains: int a(){return 0;}
  handle1 = dlmopen(LM_ID_NEWLM, "/tmp/lib-o1i6Yd.so", RTLD_NOW);
  dlinfo(handle1, RTLD_DI_LMID, &lmid);
  // handle2 contains: int b(){return 1;}
  handle2 = dlmopen(lmid, "/tmp/lib-vSyM4y.so", RTLD_NOW);
#ifdef RUN_A
  int (*A)(void);
  handle3 = dlmopen(lmid, "/tmp/lib-lAGjb2.so", RTLD_NOW);
  A = (int(*)(void))dlsym(handle3, "__wrapper_lAGjb2");
/*
  int __wrapper_lAGjb2() {
    return a();
  }
*/
  printf("%d\n", (*A)()); // output 0 as expected
  return 0;
#endif 

#ifdef RUN_B
  int (*B)(void);
  handle3 = dlmopen(lmid, "/tmp/lib-CO1YAD.so", RTLD_NOW);
  // error: /tmp/lib-CO1YAD.so: undefined symbol: b
  printf("error: %s\n", dlerror()); 
  B = (int(*)(void))dlsym(handle3, "__wrapper_CO1YAD");
  // error: ./a.out: undefined symbol: __wrapper_CO1YAD
  printf("error: %s\n", dlerror()); // 
/*
  int __wrapper_CO1YAD() {
    return b();
  }
*/
  printf("%d\n", (*B)()); // segmentation fault (core dumped)
  return 0;
#endif
}

Это test.c файл. Я компилирую, используя gcc test.c -ldl -DRUN_A/B, затем ./a.out для его запуска.

РЕДАКТИРОВАТЬ: /tmp/.so файлы

Они создаются вручную. Например, чтобы создать файл /tmp/lib-o1i6Yd.so, используя g cc: напишите код в /tmp/lib-o1i6Yd.c:

int a(){return 0;}

, скомпилируйте в .o объектный файл:

gcc -c -fpic /tmp/lib-o1i6Yd.c -o /tmp/lib-o1i6Yd.o

, затем создайте .so файл:

gcc -shared -o /tmp/lib-o1i6Yd.so /tmp/lib-o1i6Yd.o

1 Ответ

0 голосов
/ 12 апреля 2020

Manaul не ясно указывает на проблему с пространством имен (или я не совсем ясно понял) Недавно загруженные общие библиотеки, использующие dlmopen(), будут в состоянии RTLD_LOCAL по умолчанию. То есть последняя загруженная функция не может вызывать функции или использовать переменные, которые были загружены ранее. См. сообщение для получения дополнительной информации.

...