Позиционно-независимые исполняемые файлы (P IE) теперь используются по умолчанию в таких системах, как Linux и OpenBSD [1]. Таким образом, вы можете просто создать свою разделяемую библиотеку, как обычную исполняемую программу, и передать исполняемый файл в качестве аргумента объекта cc
, LD_PRELOAD
или dlopen()
так, как если бы это была разделяемая библиотека.
Единственное, что вы должны убедиться, это то, что все необходимые символы экспортированы , что НЕ по умолчанию. Таким образом, вы должны либо использовать -Wl,-E
(что приведет к экспорту всех символов), либо предоставить список экспортируемых символов через -Wl,--dynamic-list=filename
.
$ cc -Wl,--dynamic-list=<(echo '{func;};') -include stdio.h -o shared.so -xc - <<'EOT'
int main(){ printf("Shared library!\n"); }
void func(){ printf("Exported function!\n"); }
EOT
$ cc -include stdio.h -xc - -x none ./shared.so -o main <<'EOT'
int main(){ extern void func(void); func(); }
EOT
$ ./shared.so
Shared library!
$ ./main
Exported function!
Проблема -Wl,-E
означает, что он также будет экспортировать символы из файлов запуска crt*.o
, что может привести к тому, что «основной» исполняемый файл будет ссылаться на них вместо того, чтобы извлекать свою собственную копию кода запуска. Это не выглядит хорошей идеей.
Решение, которое позволит вам по-прежнему использовать -Wl,-E
вместо перечисления всех экспортируемых символов, будет использовать -Wl,--version-script=file
со сценарием версии, который локализует main
, __libc_csu*
, _start
и остальную часть зоопарка:
cc -Wl,-E -Wl,--version-script=<(echo '{local:_*;data_start;main;};') -include stdio.h -o shared.so -xc - <<'EOT'
int main(){ printf("Shared library!\n"); }
void func(){ printf("Exported function!\n"); }
EOT
$ ./main
Exported function!
[1] в некоторых системах, таких как FreeBSD или NetBSD, которые у вас еще есть использовать -pie -fPIE
для создания исполняемого файла P IE, но не связывать его с одним.