Я новичок в таблицах и библиотеках символов С++, хотел понять поведение таблицы символов. У нас есть приложение для Android с собственной поддержкой. В процессе анализа таблиц символов общих библиотек я заметил повторяющиеся символы, присутствующие в файле .so. Пожалуйста, найдите образец списка таблицы символов.
0162502c w DO .data 00000004 Base boost::asio::error::get_addrinfo_category()::instance
00aaa4f4 w DF .text 0000009c Base boost::asio::error::get_misc_category()
01626334 w DO .bss 00000004 Base guard variable for boost::asio::error::get_misc_category()::instance
00aab4d0 w DF .text 0000003c Base boost::asio::error::detail::misc_category::~misc_category()
00aab368 w DF .text 0000003c Base boost::asio::error::detail::addrinfo_category::~addrinfo_category()
00aab3a4 w DF .text 00000034 Base boost::asio::error::detail::addrinfo_category::name() const
00aab3d8 w DF .text 000000f8 Base boost::asio::error::detail::addrinfo_category::message(int) const
00aab50c w DF .text 0000003c Base boost::asio::error::detail::misc_category::~misc_category()
Здесь вы можете заметить, что следующий символ «boost::asio::error::detail::misc_category::~misc_category()» появляется дважды.
Я хотел понять, почему мы получаем повторяющиеся символы в таблице символов. Также интересно узнать, почему мое приложение работает нормально, когда есть повторяющиеся символы [какой компоновщик в идеале должен выдавать ошибку повторяющихся символов]. Также хотелось бы знать, увеличивает ли наличие повторяющихся символов в таблицах символов размер «так», что в конечном итоге приводит к увеличению размер приложения
Если это произойдет, как я могу гарантировать, что я получаю только уникальные записи в таблице символов. Примечание: мы используем clang
I am noticing duplicate symbols present in .so file
Нравится?
$ cat foo.c
int foo(void)
{
return 42;
}
Скомпилировать:
$ gcc -Wall -fPIC -c foo.c
Проверьте символы в объектном файле для foo:
$ readelf -s foo.o | grep foo
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS foo.c
8: 0000000000000000 11 FUNC GLOBAL DEFAULT 1 foo
Один удар.
Сделать общую библиотеку:
$ gcc -Wall -shared -o libfoo.so foo.o
Проверьте символы в общей библиотеке для foo:
$ readelf -s libfoo.so | grep foo
5: 000000000000057a 11 FUNC GLOBAL DEFAULT 9 foo
29: 0000000000000000 0 FILE LOCAL DEFAULT ABS foo.c
44: 000000000000057a 11 FUNC GLOBAL DEFAULT 9 foo
Теперь два удара.
Здесь нет ничего плохого. Смотрите еще часть картинки:
$ readelf -s foo.o | egrep '(foo|Symbol table|Ndx)'
Symbol table '.symtab' contains 9 entries:
Num: Value Size Type Bind Vis Ndx Name
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS foo.c
8: 0000000000000000 11 FUNC GLOBAL DEFAULT 1 foo
Объектный файл имеет одну таблицу символов, его статическую таблицу символов .symtab,
который используется компоновщиком для разрешения символов времени компоновки. Но:
$ readelf -s libfoo.so | egrep '(foo|Symbol table|Ndx)'
Symbol table '.dynsym' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
5: 000000000000057a 11 FUNC GLOBAL DEFAULT 9 foo
Symbol table '.symtab' contains 48 entries:
Num: Value Size Type Bind Vis Ndx Name
29: 0000000000000000 0 FILE LOCAL DEFAULT ABS foo.c
44: 000000000000057a 11 FUNC GLOBAL DEFAULT 9 foo
в общей библиотеке есть таблицы символов два: статическая таблица символов .symtab, например
объектный файл, а также динамическая таблица символов .dynsym, используемая загрузчиком для разрешения символов во время выполнения.
Когда вы связываете объектные файлы с общей библиотекой, компоновщик по умолчанию расшифровывает
GLOBAL символы из их .symtabs в .symtabи.dynsym общего
библиотеки, за исключением тех символов, которые имеют HIDDENвидимость в объектных файлах
(который они получают от определения с помощью атрибут скрытой видимости
при составлении).
Любые GLOBAL символы с HIDDEN видимостью в объектных файлах транскрибируются как LOCAL символы.
с DEFAULT видимостью в .symtab общей библиотеки и не расшифровываются
вообще в .dynsym общей библиотеки. Поэтому, когда общая библиотека связана с
ничего другого, ни компоновщик, ни загрузчик не видят глобальные символы, которые были HIDDEN при компиляции.
Но кроме скрытых символов, которых зачастую нет, такие же глобальные символы
появится в таблицах .symtab и .dynsym общей библиотеки. Каждый определенный символ
которое появляется в обеих таблицах, относится к одному и тому же определению.
Позже комментарии ОП
I took the symbol table by running objdump -T command, which should ideally list symbols present only in dynamic symbol table.
Это приводит нас к другому объяснению, потому что objdump -T действительно сообщает только
динамическая таблица символов (например, readelf --dyn-syms).
Обратите внимание, что символ сообщил дважды:
...
00aab4d0 w DF .text 0000003c Base boost::asio::error::detail::misc_category::~misc_category()
...
00aab50c w DF .text 0000003c Base boost::asio::error::detail::misc_category::~misc_category()
...
классифицируется w в столбце 2 (как и все остальные символы в вашем фрагменте). Что objdump означает, что это
что символ слабый.
Повторим наблюдение:
foo.hpp
#pragma once
#include <iostream>
struct foo
{
explicit foo(int i)
: _i{i}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
~foo()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int _i = 0;
};
бар.cpp
#include "foo.hpp"
foo bar()
{
return foo(2);
}
жвачка.cpp
#include "foo.hpp"
foo gum()
{
return foo(1);
}
Скомпилируйте и создайте разделяемую библиотеку:
$ g++ -Wall -Wextra -c -fPIC bar.cpp gum.cpp
$ g++ -shared -o libbargum.so bar.o gum.o
Посмотрите, какие символы динамичныйobjdump сообщает из struct foo:
$ objdump -CT libbargum.so | grep 'foo::'
00000000000009bc w DF .text 0000000000000046 Base foo::foo(int)
00000000000009bc w DF .text 0000000000000046 Base foo::foo(int)
Дублируйте слабые экспорты конструктора foo::foo(int). Так же, как то, что вы
заметил.
Хотя держись за галочку. foo::foo(int) — это сигнатура метода C++, но не
на самом деле это символ, который компоновщик может распознать. Давай сделаем это снова, на этот раз
без разборки:
$ objdump -T libbargum.so | grep 'foo'
00000000000009bc w DF .text 0000000000000046 Base _ZN3fooC1Ei
00000000000009bc w DF .text 0000000000000046 Base _ZN3fooC2Ei
Теперь мы видим символы, которые видит компоновщик, и дублирования больше не видно:
_ZN3fooC1Ei != _ZN3fooC2Ei, хотя оба символа имеют одинаковый адрес и
$ c++filt _ZN3fooC1Ei
foo::foo(int)
$ c++filt _ZN3fooC2Ei
foo::foo(int)
они оба относятся к одному и тому же, foo::foo(int). На самом деле их 5
различные символы - _ZN3fooCНEi, для 1 <= Н <= 5 - которые превращаются в foo::foo(int).
(И g++ на самом деле использует _ZN3fooC1Ei, _ZN3fooC2Ei и _ZN3fooC5Ei в объекте
файлы bar.o и gum.o).
Так что на самом деле в таблице динамических символов нет повторяющихся символов: подлый характер преобразования имен "многие к одному" просто заставляет его выглядеть именно так.
Но почему?
Боюсь, ответ на этот вопрос слишком длинный и сложный для этого.
Управляющее резюме
Компилятор GCC C++ использует два слабых символа, которые demangle одинаково ссылаться на глобальный встроенный метод класса по-разному, как часть его базовая формула для обеспечения успешного связывания глобальных встроенных методов классов в независимом от позиции коде. Это существенная проблема для любого компилятора, и формула GCC для нее не является единственно возможной. Clang имеет другой решение, которое предполагает использование синонимичных, но различных символов и поэтому не порождают иллюзорное «дублирование» символов, которые вы видели.
@Teja Как объяснялось, общая библиотека имеет таблицы символов два: символы в ее динамической таблице символов являются подмножеством символов в ее статической таблице символов.
Спасибо за терпеливость!! Я взял таблицу символов, выполнив команду objdump -T, которая в идеале должна отображать символы, присутствующие только в динамической таблице символов. Несмотря на использование флага «-T», я замечаю повторяющиеся символы, это ожидается? если да, то почему это ожидается?
@Teja Обновленный ответ может помочь
Спасибо за подробный анализ, теперь я понял, почему я вижу повторяющиеся символы [что является эффектом разборки], поэтому в вашем примере идеально, если есть еще один метод с именем «Тест» и возвращает foo (3), а затем еще одна запись будут добавлены в таблицу символов. это правда ? Ожидается ли это, даже если мы используем Clang [Обратите внимание, что мы используем clang].
@Teja Извините, но сейчас я должен ответить на этот вопрос.
Итак, исходя из приведенного выше объяснения, всегда ли ожидается наличие повторяющихся символов в таблице символов?