Динамическая загрузка без внешнего «C»

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

Как описано здесь, одним из решений является удаление искажения имени с помощью внешнего «C».

http://www.tldp.org/HOWTO/C++-dlopen/theproblem.html

Это решение имеет недостаток, заключающийся в ограничении динамически загружаемых ресурсов интерфейсами в стиле C. Динамически загруженные функции не могут, например, быть перегруженными функциями.

Какой хороший способ преодолеть это ограничение?

Одним из возможных решений было бы использование инструментов для именования исходного кода библиотеки с помощью сопровождающей функции для получения искаженных имен, когда библиотека должна быть связана. Предоставляет ли llvm инструменты для этого?

Возможно, неуклюжим решением будет функция, которая принимает сигнатуру функции, создает фиктивный код с функцией, которая имеет сигнатуру, передает в компилятор, который использовался с флагом для генерации сборки, анализирует выходные данные для получения искаженного имени и возвращает искаженное имя в виде строки. Строка может быть передана в dlsym ().

Чтобы конкретизировать проблему, вот две примеры программ, которые иллюстрируют то, что внешнее решение «C» не может динамически загрузить без изменения библиотечного кода. Первый динамически связывает библиотеку традиционным способом C ++. Второй использует длопен. Связать перегруженную функцию в первой программе просто. Нет простого способа связать перегруженную функцию во второй программе.

Программа 1: Динамическое связывание во время загрузки

main.cpp

// forward declarations of functions that will be linked
void say(int);
void say(float);

int main() {
int myint = 3;
say(myint);
float myfloat = 5.0f;
say(myfloat);
}

say.cpp

#include <iostream>

//extern "C" function signatures would collide

//extern "C" void say(int a) {
void say(int a) {
std::cout << "The int value is " << a << ".\n";
}

//extern "C" void say(float a) {
void say(float r) {
std::cout << "The float value is " << r << ".\n";
}

выход

$ ./main
The int value is 3.
The float value is 5.

Программа 2: Динамическое связывание во время выполнения

main_with_dl.cpp

#include <iostream>
#include <dlfcn.h>

int main() {
// open library
void* handle = dlopen("./say_externC.so", RTLD_LAZY);
if (!handle) {
std::cerr << "dlopen error: " << dlerror() << '\n';
return 1;
}

// load symbol
typedef void (*say_t)(int);

// clear errors, find symbol, check errors
dlerror();
say_t say = (say_t) dlsym(handle, "say");
const char *dlsym_error = dlerror();
if (dlsym_error) {
std::cerr << "dlsym error: " << dlsym_error << '\n';
dlclose(handle);
return 1;
}

// use function
int myint = 3;
say(myint);
// can't load in void say(float)
// float myfloat = 5.0f;
// say(myfloat);

// close library
dlclose(handle);
}

выход

$ ./main_with_dl
The int value is 3.

составление

Makefile

CXX = g++

all: main main_with_dl say_externC.so

main: main.cpp say.so
$(CXX) -o $@ $^

main_with_dl: main_with_dl.cpp
$(CXX) -o $@ $<

%.so : %.cpp
$(CXX) -shared -o $@ $<

.PHONY: clean
clean:
rm main main_with_dl say.so say_externC.so

4

Решение

Благодаря Mooing Duck я смог придумать решение, используя clang и вдохновленный Visual Studio.

Ключ — это макрос, предоставляемый Visual Studio и clang. Макрос __FUNCDNAME__ преобразуется в искаженное имя включающей функции. Определив функции с той же сигнатурой, что и те, которые мы хотим динамически связать, мы можем получить __FUNCDNAME__ для разрешения нужного имени mangle.

Вот новая версия программы 2, которая может вызывать как void say (int), так и void say (float).

РЕДАКТИРОВАТЬ Мытье утки дало мне больше знаний. Вот версия main_with_dl.cpp, которая работает с say.cpp в вопросе.

http://coliru.stacked-crooked.com/a/7249cc6c82ceab00

Код должен быть скомпилирован с использованием clang ++ с флагом -fms-extensions для работы __FUNCDNAME__.

2

Другие решения


По вопросам рекламы [email protected]