Как экспортировать символы из общей библиотеки - PullRequest
5 голосов
/ 16 апреля 2009

Я создал общую библиотеку (*.so), используя файлы объектного кода *.o (исходный код C), используя компилятор RVDS на хосте Windows.

Я связываю этот общий объект с приложением (используя gcc для цели ARM на хосте Linux) и получаю исполняемый файл, который при запуске генерирует ошибку сегментации. (Я знаю, я должен отладить это!)

Вместо создания общей библиотеки, если я создаю статическую библиотеку с теми же исходными файлами, а затем связываюсь с приложением, а затем выполняю приложение, оно работает нормально, как и ожидалось.

Итак, мои вопросы:

  1. Нужно ли явно экспортировать символы (функции, экспортированные в приложение) или любые другие символы в моем исходном файле, используя некоторые конструкции, чтобы он нормально работал при связывании с приложением? Что нужно и как мне это сделать?

  2. Как работает разделяемая библиотека ?, то есть будут ли адреса, по которым будут загружаться и запускаться функции, указываться в библиотеке при создании библиотеки. Как приложение (main()) разрешает адреса, по которым должны выполняться библиотечные функции?

  3. Как работает статическая библиотека, т. Е. Как происходит спецификация и разрешение адресов в случае статической библиотеки?

Ответы [ 3 ]

12 голосов
/ 16 апреля 2009

Вот как это работает в Linux:

1) Нет, вам не нужно ничего делать. Однако вы можете ограничить экспорт переменных с помощью аргумента командной строки gcc -fvisibility и явно пометить экспортированные записи атрибутом видимости.

2) Исполняемый файл будет иметь таблицу всех функций, которые он импортирует (это все функции с видимостью по умолчанию). Загрузчик / компоновщик выберет адрес для загрузки библиотек и заполнит эту таблицу непосредственно перед запуском, вызовы этих функций являются косвенными вызовами. (Обратите внимание, что это относится и к общим объектам)

3) Статическое связывание выполняется во время соединения (то есть после компиляции). Фактические адреса подставляются в сборку и являются прямыми вызовами.

Примечание: есть вещь, называемая PIC (позиционно-независимый код). AFAIK, это касается ссылок на данные / функции в одном и том же общем объекте, поэтому компоновщик не должен перезаписывать половину кода библиотеки при загрузке библиотеки, так как код не делает никаких абсолютных ссылок на ее собственные данные. Вы можете попробовать поэкспериментировать с этим.

3 голосов
/ 02 апреля 2011
  1. Вам не нужно экспортировать символы с gcc, так как он экспортирует все символы по умолчанию; RVDS может или не может сделать то же самое, однако. Проверьте документацию компилятора RVDS (попробуйте настроить его для вывода « Перемещаемый ELF »?)

  2. Совместно используемые библиотеки в Linux должны быть перемещаемыми, так как базовый адрес определяется во время выполнения. Генерация независимого от позиции кода идеальна, так как уменьшает объем работы, необходимой для перемещения библиотеки. Если ваша библиотека не перемещаема, то приведет к краху (другими словами, не удаляйте информацию о перемещении из ваших объектных файлов перед созданием динамической библиотеки). Символы преобразуются в адреса во время выполнения после выбора базового адреса и перемещения внутренних ссылок.

  3. Со статическими библиотеками все разрешение символов, перемещение и назначение адресов загрузки происходит во время компиляции.

Мое единственное предположение заключается в том, что код, который выдает ваш компилятор, не может быть перемещен во время выполнения. Для меня загадка, как это могло бы произойти, не нарушая и статические библиотеки ...

Если вы генерируете статическую библиотеку и разделяемую библиотеку непосредственно из RVDS, одним из вариантов будет попытка преобразовать эту статическую библиотеку в разделяемую библиотеку:

gcc -shared -o libfoo.so libfoo.a

Если это поможет, то компоновщик совместно используемой библиотеки RVDS (или его конфигурация), вероятно, поврежден.

0 голосов
/ 20 мая 2009

Знаете ли вы что-нибудь о причине аварии?

Одна из возможностей, если вы загружаете разделяемую библиотеку динамически (например, через dlopen()), заключается в том, что вы предполагаете, что библиотека загружена нормально, когда она этого не делала, а затем пытаетесь выполнить функции через нулевые указатели.

...