Смешивание рисунков и не-PIC-объектов в общей библиотеке
-
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 и без него в общем объекте (это использовалось годами). Я не знаю достаточно о рисунке, чтобы знать, хорошая ли это идея/умная, и я предполагаю, что в этом случае это не нужно, а скорее происходит, потому что кому -то было наплевать, чтобы узнать правильный способ сделать это при прикреплении На новых вещах в сборку.
Мой вопрос:
- Это безопасно
- Это хорошая идея
- Какие потенциальные проблемы могут возникнуть в результате
- Если я переключу все на картинку, есть ли какие-нибудь неочевидные 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 и каждой библиотеки, которая включала оскорбительный заголовок-отсюда и двойной.