Как посмотреть список символов (функций, классов) в .so файле на Linux?
Основной ответ: используйте утилиты nm и objdump
Для просмотра символов в .so файле в Linux есть несколько стандартных инструментов. Самый популярный — nm. Он показывает имена символов, их типы и адреса. Дополнительно можно использовать objdump -T для просмотра только динамических (экспортированных) символов.
1. Команда nm -D (динамические символы)
Так как .so файл — это динамическая библиотека, нас интересуют только экспортированные символы. Используйте флаг -D:
nm -D libmylib.so
Вывод будет примерно таким:
0000000000001119 T _Z3addii
0000000000001109 T _Z5hellov
U __cxa_finalize@GLIBC_2.17
U __gxx_personality_v0@CXXABI_1.3
U _Unwind_Resume@GCC_3.0
w __cxa_finalize@GLIBC_2.17
Здесь T означает, что символ определён в коде (text section). Вы видите искажённые имена C++: _Z3addii — это add(int, int), а _Z5hellov — hello(). U — неопределённые символы (из других библиотек).
2. Декодирование имён (demangling)
Чтобы получить читаемые имена, добавьте флаг -C:
nm -DC libmylib.so
Результат:
0000000000001119 T add(int, int)
0000000000001109 T hello()
U __cxa_finalize@GLIBC_2.17
U __gxx_personality_v0@CXXABI_1.3
U _Unwind_Resume@GCC_3.0
Теперь видно, что функции add и hello экспортируются с искажёнными именами (C++ mangling).
3. Использование objdump -T
Альтернативный способ — objdump. Он показывает динамическую таблицу символов:
objdump -T libmylib.so
Вывод:
libmylib.so: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000 w D *UND* 0000000000000000 __cxa_finalize
0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000001109 g F .text 0000000000000015 _Z5hellov
0000000000001119 g F .text 000000000000001a _Z3addii
Флаг g означает global (доступен для других модулей). F — функция.
4. Если вы хотите экспортировать символы без искажения (как в C)
Для совместимости с C или для простоты используйте extern "C". Измените объявление в заголовочном файле:
// mylib.h
#pragma once
extern "C" {
void hello();
int add(int a, int b);
}
После пересборки nm -D покажет:
0000000000001109 T hello
0000000000001119 T add
Имена не искажаются. Это удобно, если библиотеку будут использовать программы на C или других языках.
5. Просмотр всех символов (включая статические)
Если нужно увидеть все символы (не только экспортированные), используйте nm без флага -D:
nm libmylib.so
Вы увидите больше строк, включая внутренние символы (например, статические функции, глобальные переменные).
Дополнительные советы
- Фильтрация:
nm -DC libmylib.so | grep " T "— покажет только определённые функции. - Сравнение: Если у вас есть две версии .so, сравните списки символов с помощью
diff. - Проверка видимости: Символы с флагом
g(global) — экспортируются, сl(local) — скрыты.
Теперь вы можете легко проверить, какие функции доступны в вашей библиотеке, и отладить проблемы с компоновкой.
<<Альтернативный ответ: использование readelf и утилит из binutils
Если nm или objdump недоступны, или вам нужна более детальная информация, используйте readelf. Эта утилита входит в состав GNU binutils и показывает структуру ELF-файла.
Команда readelf -s (все символы)
readelf -s libmylib.so
Вывод будет содержать полную таблицу символов, включая секции, размеры и типы. Для экспортированных символов лучше использовать readelf --dyn-syms:
readelf --dyn-syms libmylib.so
Пример:
Symbol table '.dynsym' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
5: 0000000000001109 15 FUNC GLOBAL DEFAULT 13 _Z5hellov
6: 0000000000001119 26 FUNC GLOBAL DEFAULT 13 _Z3addii
Здесь Bind: GLOBAL — символ доступен для других модулей, Type: FUNC — функция.
Почему это может быть полезно?
- Детализация:
readelfпоказывает размер функции (в байтах), что помогает оценить её сложность. - Секции: Вы можете увидеть, в какой секции находится символ (например, .text для кода).
- Проверка версий: Если библиотека использует версионирование символов (symbol versioning),
readelfпокажет это.
Сравнение с nm
Для быстрой проверки nm -DC удобнее, так как он сразу декодирует имена. Но если вам нужно автоматизировать анализ (например, в скриптах), readelf даёт более структурированный вывод, который легче парсить. Также readelf работает с файлами, которые могут быть повреждены или не полностью загружены.
Дополнительно: проверка зависимостей
Чтобы увидеть, от каких библиотек зависит ваш .so, используйте:
readelf -d libmylib.so | grep NEEDED
Это покажет список нужных .so файлов (например, libstdc