Как напечатать строку версии / выполнить какой-либо код при выполнении моей библиотеки (.so)? - PullRequest
1 голос
/ 09 апреля 2020

Я видел некоторые версии lib c .so, которые при запуске из командной строки будут печатать строку версии, например так:

$ /lib/libc.so.6
GNU C Library (Buildrood) stable release version 2.30.
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTIBILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.4.0.
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
<https://www.gnu.org/software/libc/bugs.html>.

Очевидно, что есть какая-то точка входа в эту библиотеку, сохраняя при этом main() для пользовательских программ.

Я хотел бы сделать это для моей собственной библиотеки, чтобы распечатать полезную информацию о том, как она была скомпилирована, что она поддерживает и т.д. c. Мои поиски по этому поводу не были плодотворными, но, возможно, я ищу не ту вещь. Как я могу это сделать?

1 Ответ

2 голосов
/ 09 апреля 2020

Позиционно-независимые исполняемые файлы (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, но не связывать его с одним.

...