Допустимо ли связывать не PIC-объекты в исполняемый файл с PIC-объектами?

Я добавляю локальную переменную потока в пару объектных файлов, которые всегда связаны непосредственно с исполняемыми файлами. Эти объекты никогда не будут включены в общую библиотеку (и можно с уверенностью предположить, что это сохранится в обозримом будущем). Это означает, что флаг -fPIC не требуется для этих объектов, верно?

Наша кодовая база по умолчанию имеет флаг -fPIC для всех объектов. Многие из них включены в разделяемые библиотеки, поэтому использование -fPIC имеет смысл. Однако этот флаг представляет проблему при отладке новой локальной переменной потока, потому что GDB дает сбой при переходе через локальную переменную потока с параметром -fPIC. Если я удалю -fPIC из этих нескольких объектных файлов с новой локальной переменной потока, я смогу отладить правильно.

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

Безопасно ли в этом случае связывать не PIC-объекты в исполняемый файл, созданный с помощью PIC-объектов и библиотек? Может быть, есть официальное заявление от GCC о том, что это безопасно, но я не могу его найти.

РЕДАКТИРОВАТЬ: Двоичное исправление gcc, чтобы избежать этой ошибки, не является решением в краткосрочной перспективе. Переключение компилятора в Linux не является возможным решением.

1 ответ

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

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

Чистое разделение между Compiler + Linker должно гарантировать, что флаги не будут иметь значения (вне различий в производительности). Я был бы осторожен с жестким LTO, в прошлом было несколько проблем с различными настройками компилятора.

Как уже говорилось, я потратил некоторое время на изучение этого и написал несколько документов об ELF и динамических загрузчиках. Вы нигде не найдете явного упоминания о связывании PIC/non-PIC, но процесс связывания действительно не заботится о настройках компилятора для входных данных, действительный код останется действительным кодом.

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

Это возможно почти всегда, но иногда требуется хитрость

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