Смешивание рисунков и не-PIC-объектов в общей библиотеке

StackOverflow https://stackoverflow.com/questions/8331456

  •  26-10-2019
  •  | 
  •  

Вопрос

Этот вопрос связан с Вот этот а также его ответ.

Я только что обнаружил некоторое уродство в сборке, над которой я работаю. Ситуация выглядит как следующее (написано в формате Gmake); Обратите внимание, что это конкретно применяется к 32-битной модели памяти на аппаратном обеспечении SPARC и X86:

OBJ_SET1  := some objects
OBJ_SET2  := some objects

# note: OBJ_SET2 doesn't get this flag
${OBJ_SET1} : CCFLAGS += -PIC

${OBJ_SET1} ${OBJ_SET2} : %.o : %.cc
  ${CCC} ${CCFLAGS} -m32 -o ${@} -c ${<}

obj1.o       : ${OBJ_SET1}
obj2.o       : ${OBJ_SET2}
sharedlib.so : obj1.o obj2.o
obj1.o obj2.o sharedlib.so :
  ${LINK} ${LDFLAGS} -m32 -PIC -o ${@} ${^}

Очевидно, что он может работать для смешивания объектов, скомпилированных с PIC и без него в общем объекте (это использовалось годами). Я не знаю достаточно о рисунке, чтобы знать, хорошая ли это идея/умная, и я предполагаю, что в этом случае это не нужно, а скорее происходит, потому что кому -то было наплевать, чтобы узнать правильный способ сделать это при прикреплении На новых вещах в сборку.

Мой вопрос:

  1. Это безопасно
  2. Это хорошая идея
  3. Какие потенциальные проблемы могут возникнуть в результате
  4. Если я переключу все на картинку, есть ли какие-нибудь неочевидные Gotchas, за которые я бы захотел следить.
Это было полезно?

Решение

Забыл, я даже написал этот вопрос.

Некоторые объяснения в первую очередь:

  • Не-PIC-код может быть загружен ОС в какую-либо позицию в памяти в [Большинство?] Modern OSS. После того, как все загружено, он проходит фазу, которая исправляет текстовый сегмент (где заканчивается исполняемый файл), поэтому он правильно учитывает глобальные переменные; Чтобы справиться с этим, текстовый сегмент должен быть доступен для записи.
  • Исполняемые данные PIC могут быть загружены ОС и совместно с несколькими пользователями/процессами. Однако, чтобы сделать это, текстовый сегмент должен быть только для чтения, что означает отсутствие исправлений. Код составлен для использования глобальной таблицы смещения (GOT), чтобы он мог решать глобальные значения по сравнению с GOT, что облегчает необходимость исправлений.
  • Если общий объект построен без рисунков, хотя настоятельно рекомендуется, он не кажется, что он строго необходим; Если ОС должна исправить текстовый сегмент, то она вынуждена загрузить его в память, которая помеченная считываемая записка ... что предотвращает совместное использование между процессами/пользователями.
  • Если исполняемый двоичный файл построен / с / рис, я не знаю, что идет не так, под капюшоном, но я стал свидетелем того, как несколько инструментов становятся нестабильными (загадочные аварии и тому подобное).

Ответы:

  • Смешивание PIC/NON-PIC или использование PIC в исполняемых файлах может вызвать трудности и отслеживать нестабильность. У меня нет технического объяснения, почему.
    • ... чтобы включить сегфалты, ошибки автобусов, коррупцию стека и, вероятно, больше, кроме того.
  • Не PIC в общих объектах, вероятно, не вызовут каких-либо серьезных проблем, хотя это может привести к большему количеству оперативной памяти, если библиотека используется много раз в разных процессах и/или пользователях.

Обновление (4/17)

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

/*header.h*/
#include <map>
typedef std::map<std::string,std::string> StringMap;
StringMap asdf;

/*file1.cc*/
#include "header.h"

/*file2.cc*/
#include "header.h"

int main( int argc, char** argv ) {
  for( int ii = 0; ii < argc; ++ii ) {
    asdf[argv[ii]] = argv[ii];
  }

  return 0;
}

... тогда:

$ g++ file1.cc -shared -PIC -o libblah1.so
$ g++ file1.cc -shared -PIC -o libblah2.so
$ g++ file1.cc -shared -PIC -o libblah3.so
$ g++ file1.cc -shared -PIC -o libblah4.so
$ g++ file1.cc -shared -PIC -o libblah5.so

$ g++ -zmuldefs file2.cc -Wl,-{L,R}$(pwd) -lblah{1..5} -o fdsa
#     ^^^^^^^^^
#     This is the evil that made it possible
$ args=(this is the song that never ends);
$ eval ./fdsa $(for i in {1..100}; do echo -n ${args[*]}; done)

Этот конкретный пример может не в конечном итоге рухнуть, но это в основном ситуация, которая существовала в коде этой группы. Если это делает Сбой, вероятно, будет в деструкторе, как правило, двойная ошибка.

Много лет назад они добавили -zmuldefs к их сборке, чтобы избавиться от множества определенных ошибок символов. Компилятор издает код для запуска конструкторов/деструкторов на глобальных объектах. -zmuldefs Заставляет их жить в том же месте в памяти, но он по-прежнему управляет конструкторами/деструкторами один раз для EXE и каждой библиотеки, которая включала оскорбительный заголовок-отсюда и двойной.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top