Да, рассмотрев свой собственный исполняемый файл (/proc/self/exe
), используя, например, libbfd
или библиотеку синтаксического анализа файлов ELF, чтобы самостоятельно анализировать сами символы. По сути, вы должны написать код C, который делает эквивалент чего-то вроде
env LANG=C LC_ALL=C readelf -s executable | awk '($5 == "LOCAL" && $8 ~ /^[^_]/ && $8 !~ /\./)'
Насколько мне известно, динамический интерфейс компоновщика в Linux (<dlfcn.h>
) не возвращает адреса для статического (локального ).
Простым и довольно надежным подходом является выполнение readelf
или objdump
из вашей программы. Обратите внимание, что вы не можете указать путь псевдофайла /proc/self/exe
к ним, поскольку он всегда ссылается на собственный исполняемый файл процесса. Вместо этого вы должны использовать, например. realpath("/proc/self/exe", NULL)
, чтобы получить динамически выделенный абсолютный путь к текущему исполняемому файлу, который вы можете предоставить команде. Вы также определенно хотите, чтобы среда содержала LANG=C
и LC_ALL=C
, так что вывод команды легко анализируется (а не локализован на любой язык, который предпочитает текущий пользователь). Это может показаться немного глупым, но для этого требуется установить пакет binutils
, и вам не нужно обновлять свою программу или библиотеку, чтобы идти в ногу с последними событиями, поэтому я думаю, что это в целом довольно Хороший подход.
Хотелось бы привести пример?
Одним из способов облегчения создания отдельных массивов с информацией о символе во время компиляции. В принципе, после создания объектных файлов отдельный исходный файл динамически генерируется путем запуска objdump
или readelf
над связанными объектными файлами, генерируя массив имен и указателей, похожих на
const struct {
const char *const name;
const void *const addr;
} local_symbol_names[] = {
/* Filled in using objdump or readelf and awk, for example */
{ NULL, NULL }
};
возможно, с простой функцией поиска, экспортированной в файл заголовка, так что, когда последний исполняемый файл связан, он может легко и эффективно получать доступ к массиву локальных символов.
Он дублирует некоторые данные, поскольку такая же информация уже находится в исполняемом файле, и если я правильно помню, вы должны сначала связать конечный исполняемый файл с массивом-заглушкой, чтобы получить фактические адреса для символов, а затем повторно связать с массивом символов, что делает его немного сложным время компиляции. Но это позволяет избежать зависимости от времени выполнения binutils
.