До сих пор я предполагал, что объекты со статической связью (т.е. статические функции и статические переменные) в C не конфликтуют с другими объектами (статической или внешней связи) в других единицах компиляции (например, файлах .c), поэтому я использовал "short "имена для внутренних вспомогательных функций, а не все с префиксом имени библиотеки. Недавно у пользователя моей библиотеки произошел сбой из-за конфликта имен с экспортированной функцией из другой общей библиотеки. При расследовании выяснилось, что некоторые из моих статических функций являются частью таблицы символов общей библиотеки. Поскольку это происходит с несколькими основными версиями 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?





Строчная буква во втором столбце вывода nm означает, что они локальные (если бы они были в верхнем регистре, это была бы другая история).
Эти символы не будут конфликтовать с другими символами с тем же именем и AFAIK, в основном существуют только для целей отладки.
Локальные символы не будут попадать в динамическую таблицу символов (печатаемую с помощью nm -D, но только в разделяемых библиотеках), и они совместимы с strip вместе с экспортируемыми символами (заглавными буквами во втором столбце вывода nm), которые не являются динамическими.
(Как вы узнали из книги Drepper «Как писать общие библиотеки», вы можете управлять видимостью с помощью -fvisibility=(default|hidden) (не следует использовать защищенные) и с помощью атрибутов видимости.)
FWIW оказалось, что фактически конфликтующие функции были не моими статическими функциями, а скорее общедоступными функциями, вызываемыми моими статическими функциями. В моем собственном коде использовалась одна библиотека JSON (связанная как общая библиотека, назовем ее a), а в другом коде использовалась другая библиотека JSON (также связанная как общая библиотека, назовем ее b); между ними произошло какое-то столкновение имен. Мы работали над этим, статически связав библиотеку JSON a с моей собственной общей библиотекой. Статическая версия библиотеки JSON a должна быть собрана с -fPIC (configure --with-pic), чтобы это работало.
Спасибо, это хоть немного проясняет ситуацию, особенно то, что касается
strip. Пробовал; он удалил местные символы, как вы и предполагали. Похоже, что потребуются дальнейшие исследования относительно того, что именно происходит во время выполнения.