До сих пор я предполагал, что объекты со статической связью (то есть статическими функциями и статическими переменными) в C не сталкиваются с другими объектами (статической или внешней связью) в других единицах компиляции (то есть .c
файлах), поэтому яиспользовал «короткие» имена для внутренних вспомогательных функций вместо того, чтобы ставить префикс перед именем библиотеки.Недавно у пользователя моей библиотеки произошел сбой из-за конфликта имен с экспортированной функцией из другой общей библиотеки.В ходе расследования выяснилось, что некоторые из моих статических функций являются частью таблицы символов разделяемой библиотеки.Так как это происходит с несколькими основными версиями GCC, я предполагаю, что я что-то упустил (такая серьезная ошибка была бы замечена и исправлена).
Мне удалось привести ее к следующему минимальному примеру:
#include <stdbool.h>
#include <stdlib.h>
bool ext_func_a(void *param_a, char const *param_b, void *param_c);
bool ext_func_b(void *param_a);
static bool bool_a, bool_b;
static void parse_bool_var(char *doc, char const *var_name, bool *var)
{
char *var_obj = NULL;
if (!ext_func_a(doc, var_name, &var_obj)) {
return;
}
*var = ext_func_b(var_obj);
}
static void parse_config(void)
{
char *root_obj = getenv("FOO");
parse_bool_var(root_obj, "bool_a", &bool_a);
parse_bool_var(root_obj, "bool_b", &bool_b);
}
void libexample_init(void)
{
parse_config();
}
И статическая переменная bool_a
, и статическая функция parse_bool_var
видны в таблице символов объектного файла и общей библиотеки:
$ gcc -Wall -Wextra -std=c11 -O2 -fPIC -c -o example.o example.c
$ objdump -t example.o|egrep 'parse_bool|bool_a'
0000000000000000 l O .bss 0000000000000001 bool_a
0000000000000000 l F .text 0000000000000050 parse_bool_var
$ gcc -shared -Wl,-soname,libexample.so.1 -o libexample.so.1.1 x.o -fPIC
$ nm libexample.so.1.1 |egrep 'parse_bool|bool_a'
0000000000200b79 b bool_a
0000000000000770 t parse_bool_var
Я погрузился в C11, Ульрих Дреппер"Как писать общие библиотеки" и несколько других источников, объясняющих видимость символов, но я все еще в замешательстве.Почему bool_a
и parse_bool_var
попадают в динамическую таблицу символов, даже если они объявлены static
?