Совместно используемые библиотеки C ++ имеют повторяющиеся символы - PullRequest
0 голосов
/ 18 февраля 2019

Я новичок в таблицах символов и библиотеках 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

1 Ответ

0 голосов
/ 18 февраля 2019

Я замечаю повторяющиеся символы, присутствующие в .so файле

Как это?

$ 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 из их .symtab в .symtab и .dynsym общей библиотеки, за исключением тех символов, которые имеют HIDDEN видимость в объектных файлах (которые они получают, будучи определенными с атрибутом скрытой видимости при компиляции).

Любые GLOBAL символы с HIDDEN видимостью в объектных файлах транскрибируются как LOCAL символы с DEFAULT видимостью в .symtab общей библиотеки и не транскрибируютсяв .dynsym общей библиотеки вообще.Поэтому, когда совместно используемая библиотека связана с чем-либо еще, ни компоновщик, ни загрузчик не могут видеть глобальные символы, которые были HIDDEN при компиляции.

Но кроме скрытых символов, которых часто нет,такие же глобальные символы появятся в таблицах .symtab и .dynsym общей библиотеки.Каждый определенный символ, который появляется в обеих таблицах, обращается к одному и тому же определению.

Позже, комментарии OP

Я взял таблицу символов, выполнив команду objdump -T,который в идеале должен перечислять символы, присутствующие только в динамической таблице символов.

Это приводит нас к другому объяснению, потому что 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;
};

bar.cpp

#include "foo.hpp"

foo bar()
{
    return foo(2);
}

gum.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 N Ei, для 1 <= <em>N <= 5 - которые превращаются в <code>foo::foo(int).(И g++ фактически использует _ZN3fooC1Ei, _ZN3fooC2Ei и _ZN3fooC5Ei в объектных файлах bar.o и gum.o).

Таким образом, на самом деле в динамической таблице символов нет дублирующихся символов: хитрая природа сопоставления имен и имен позволяет просто так выглядеть.

Но почему?

Боюсь, ответ на этот вопрос здесь слишком длинный и сложный.

Резюме

TheКомпилятор GCC C ++ использует два слабых символа, которые идентично разделяются, чтобы по-разному ссылаться на глобальный встроенный метод класса , как частьего фондовая формула для обеспечения возможности успешного связывания глобальных встроенных методов класса в позиционно-независимом коде.Это неотъемлемая проблема для любого компилятора, и формула GCC для нее не единственно возможная.У Clang есть другое решение, которое включает в себя использование синонимичных, но различных символов, и поэтому не приводит к иллюзорному «дублированию» символов, которые вы видели.

...