Совместно используемые библиотеки C++ имеют повторяющиеся символы

Я новичок в таблицах и библиотеках символов С++, хотел понять поведение таблицы символов. У нас есть приложение для 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

4
0
1 838
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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 19.02.2019 04:57

@Teja Как объяснялось, общая библиотека имеет таблицы символов два: символы в ее динамической таблице символов являются подмножеством символов в ее статической таблице символов.

Mike Kinghan 19.02.2019 08:02

Спасибо за терпеливость!! Я взял таблицу символов, выполнив команду objdump -T, которая в идеале должна отображать символы, присутствующие только в динамической таблице символов. Несмотря на использование флага «-T», я замечаю повторяющиеся символы, это ожидается? если да, то почему это ожидается?

Teja 19.02.2019 10:05

@Teja Обновленный ответ может помочь

Mike Kinghan 19.02.2019 21:14

Спасибо за подробный анализ, теперь я понял, почему я вижу повторяющиеся символы [что является эффектом разборки], поэтому в вашем примере идеально, если есть еще один метод с именем «Тест» и возвращает foo (3), а затем еще одна запись будут добавлены в таблицу символов. это правда ? Ожидается ли это, даже если мы используем Clang [Обратите внимание, что мы используем clang].

Teja 20.02.2019 05:08

@Teja Извините, но сейчас я должен ответить на этот вопрос.

Mike Kinghan 20.02.2019 08:32

Другие вопросы по теме