Я работаю над личным проектом, в котором мне нужно перехватывать API-интерфейсы Linux, такие как open()
, read()
и т. д., и я хотел бы провести по ним некоторый анализ данных. Мне нужно будет сохранить структуру данных C++ std::map
в библиотеке, которая будет обновляться потокобезопасным способом.
Поскольку я хочу использовать std::map
C++, я подумывал написать библиотеку (.so
) для предварительной загрузки с использованием C++, а перед перехватываемыми функциями будет стоять extern "C"
, чтобы предотвратить искажение имен компилятором C++.
Но правильный ли это подход? Должен ли я написать общую библиотеку исключительно на C и реализовать структуру данных map
с нуля?
@StreveFord Большое спасибо :) Я отредактировал заголовок вопроса :)
Вам нужна ваша программа для предварительной загрузки общей библиотеки (в Linux нет DLL) или вам нужна библиотека, которая предварительно загружает некоторый код?
Напоминание: глобальные и статические переменные будут инициализированы раньше main()
.
Для языка C вы можете написать собственное двоичное дерево или получить библиотеку.
@ThomasMatthews Да, я мог бы написать двоичное дерево с нуля или использовать библиотеку :) Но я хотел знать, могу ли я использовать расширенные возможности STL (C++) в моей библиотеке LD_PRELOAD, которые могут подключать API
это правильный подход?
В этом подходе нет ничего плохого, но он может усложниться (см. ниже).
Должен ли я написать общую библиотеку исключительно на C и реализовать структуру данных карты с нуля?
Это позволит избавиться от многих потенциальных осложнений.
Так в чем же сложности?
Чтобы использовать std::map
, вам придется связать предварительную загрузку .so
с libstdc++.so.6
, которая попытается инициализировать себя раньше, чем это сделает ваша библиотека.
А libstdc++
большой и сложный. Я не удивлюсь, если его инициализация вызовет open()
, read()
и т. д.
Это означает, что ваша библиотека должна быть готова обрабатывать эти вызовы, прежде чем libstdc++.so
сможет работать.
Следующая последовательность действий может привести к сбою вашей библиотеки:
libstdc++.so
вызывает open
, который вставлен вашей библиотекойstd::map
, который снова вызывает libstdc++.so
,open
вернется в libstdc++
.Возможны многие варианты вышеизложенного, и какой вариант вы получите, может зависеть от точного набора функций, которые вы вставляете, набора вызовов, которые вы совершаете в libstdc++
, и версии libstdc++
.
То есть он может работать нормально, пока вы не попробуете его в другой системе, или пока вы не обновите свой g++
, или пока вы не добавите новый интерпозер. Или может вообще не работать.
Он определенно не предназначен для работы, поэтому вы будете играть в русскую рулетку.
P.S. В моей системе следующая программа:
int main() { return 0; }
построенный с помощью g++ main.cc -Wl,--no-as-needed
и запущенный с помощью LD_DEBUG=bindings ./a.out
, показывает, что мой libstdc++.so
вызывает следующие libc.so.6
функции:
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__libc_single_threaded' [GLIBC_2.32]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__cxa_finalize' [GLIBC_2.2.5]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `stdin' [GLIBC_2.2.5]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `stderr' [GLIBC_2.2.5]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `stdout' [GLIBC_2.2.5]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `pthread_once' [GLIBC_2.34]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__newlocale' [GLIBC_2.2.5]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__uselocale' [GLIBC_2.3]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `wctob' [GLIBC_2.2.5]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `btowc' [GLIBC_2.2.5]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__wctype_l' [GLIBC_2.2.5]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__cxa_atexit' [GLIBC_2.2.5]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `secure_getenv' [GLIBC_2.17]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `malloc' [GLIBC_2.2.5]
1926652: binding file /lib/x86_64-linux-gnu/libstdc++.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `fflush' [GLIBC_2.2.5]
Как видите, open
и read
не вызываются, а malloc
и fflush
вызываются, поэтому их вставка может вызвать проблемы.
Большое спасибо за этот замечательный ответ! :) Спасибо, что нашли время проверить все, прежде чем дать ответ :)
Я думаю, что тебя минусуют, потому что ты спрашиваешь мнения. Измените его, чтобы спросить, можете ли вы написать предварительную загрузку на C++, и есть ли что-нибудь помимо
extern "C"
, что вам нужно сделать особенно.