c - статические - установка библиотек linux




Программа Linux C: как найти библиотеку, к которой принадлежит функция (4)

Скажите во время выполнения, я хочу узнать, где определена функция «printf». Как мне это сделать? Моя первая попытка состояла в том, чтобы распечатать адрес «printf» и сравнить его с отображением виртуального адреса процесса:

моя программа:

#include <stdio.h>
#include <unistd.h>

void main()
{
    printf("address of printf is 0x%X\n", printf);
    printf("pid is  %d\n", getpid());
    while (1);
}

выход:

-bash-4.1$ ./a &
[1] 28837
-bash-4.1$ address of printf is 0x4003F8
pid is  28837

Однако это говорит о том, что функция определена в моей собственной программе!

-bash-4.1$ head /proc/28837/maps 
00400000-00401000 r-xp 00000000 08:06 6946857                            /data2/temp/del/a      <<<<<<< Address 0x4003F8 is in my own program?
00600000-00601000 rw-p 00000000 08:06 6946857                            /data2/temp/del/a
397ec00000-397ec20000 r-xp 00000000 08:11 55837039                       /lib64/ld-2.12.so
397ee1f000-397ee20000 r--p 0001f000 08:11 55837039                       /lib64/ld-2.12.so
397ee20000-397ee21000 rw-p 00020000 08:11 55837039                       /lib64/ld-2.12.so
397ee21000-397ee22000 rw-p 00000000 00:00 0 
397f000000-397f18a000 r-xp 00000000 08:11 55837204                       /lib64/libc-2.12.so
397f18a000-397f38a000 ---p 0018a000 08:11 55837204                       /lib64/libc-2.12.so
397f38a000-397f38e000 r--p 0018a000 08:11 55837204                       /lib64/libc-2.12.so
397f38e000-397f38f000 rw-p 0018e000 08:11 55837204                       /lib64/libc-2.12.so

Разве это не вызов в libc? Как узнать, откуда взялась эта «printf» или любая другая функция?


Скажите во время выполнения, я хочу узнать, где определена функция «printf».

В общем и абсолютном выражении вы, вероятно, не сможете (по крайней мере, не легко). Данная функция может быть определена в нескольких библиотеках (для printf это маловероятно, поскольку она находится в стандартной библиотеке C).

Если вы построите свою систему Linux с нуля , вы можете мечтать о том, что что-то обрабатывает каждую библиотеку во время сборки (например, при создании каждой общей библиотеки вы можете получить все свои общедоступные имена с помощью nm(1) и поместить их в некоторую базу данных). На сегодняшний день это еще не сделано, но некоторые исследовательские проекты идут в этом направлении (в частности, softwareheritage и другие в 2019 году).

Кстати, у вас может быть несколько библиотек, определяющих printf . Например, если вы устанавливаете GNU glibc и musl-libc на свой компьютер (или, более вероятно, если у вас есть несколько вариантов glibc ). Конкретная программа вряд ли будет использовать оба (но все же теоретически, возможно, и их обоих).

Возможно, вам нужна функция dladdr(3) Linux. Из некоторого заданного адреса он сообщает об этом общему объекту.

функция определена в моей собственной программе

Да. Узнайте больше о динамической компоновке . В частности, прочитайте документ Drepper « Как писать общие библиотеки» . Поймите, какова цель таблицы связывания процедур .


  1. указатели printf с использованием %p , а не %X :

    printf("address of printf is 0x%p\n", printf);
  2. Если вы скомпилируете статический libc, то printf будет связан с вашим двоичным

  3. при компиляции с

    gcc -fPIC a.c # (older gccs)
    ...
    gcc -fno-plt a.c # (gcc 6 and above)

    выходы:

    address of printf is 0x0x7f40acb522a0

    который находится внутри

    7f40acaff000-7f40accc2000 r-xp 00000000 fd:00 100687388                  /usr/lib64/libc-2.17.so

Читайте, что здесь означает @plt? чтобы узнать больше об этом.


Во время выполнения вы можете использовать gdb для этого:

(terminal 1)$ ./a
pid is  16614
address of printf is 0x400450

(terminal 2)$ gdb -p 16614
(...)
Attaching to process 16614
(...)
0x00000000004005a4 in main ()
(gdb)

(gdb) info sym printf
printf in section .text of /lib/x86_64-linux-gnu/libc.so.6

Если вы не хотите прерывать свою программу или не хотите использовать gdb , вы также можете запросить ld.so для вывода некоторой информации об отладке:

(terminal 1)$ LD_DEBUG=bindings LD_DEBUG_OUTPUT=syms ./a
pid is  17180
address of printf is 0x400450

(terminal 2)$ fgrep printf syms.17180
    17180:  binding file ./a [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `printf' [GLIBC_2.2.5]

Вы можете сделать это статически. Нет необходимости выполнять:

$ readelf -Ws a.out | grep printf
      1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND [email protected]_2.2.5 (2)
     51: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND [email protected]@GLIBC_2.2.5




linux