LINUX.ORG.RU

Линковка при сборке, линковка при запуске. Всё сложно.

 , ,


2

2

Есть библиотека, которая может собираться в двух исполнениях, статической или динамической. Назову её условно libseveral. libseveral.so установлена в операционной системе. Есть разделяемые библиотеки (.so), установленные в операционной системе, они ссылаются прямо или косвенно на libseveral.so в динамическом исполнении и тянут её в память за собой, назову их - libanother1.so, libanother2.so и libanother3.so. Есть мой проект разделяемой биллиотеки (назову libroot.so), которая: а) линкует libseveral.a в статическом исполнении, б) линкует системные libanother1.so, libanother2.so и libanother3.so. В результате, libseveral.a в бинарник не попадает, а тот оказывается слинкован с libseveral.so через остальные библиотеки. Я приблизительно понимаю почему, но не уверен.

libseveral.a
libseveral.so

libanother1 -> libseveral.so
libanother2 -> libanother3.so
libanother3 -> libseveral.so

libroot.so -> libseveral.a
libroot.so -> libanother1.so
libroot.so -> libanother2.so

Вопрос. Существует ли способ сделать так, что бы к libroot.so было прилинковано всё содержимое libseveral.a, а остальные библиотеки, libanother… которые линкуются в рантайме не загружали за собой libseveral.so, а вызывали вместо этого libseveral.a, слинкованный в libroot.so? Менять библиотеки, лежащие в операционной системе нельзя, так же как и устанавливать в систему ничего, кроме libroot.so - требование. Мне необходимо, что бы всё прилинкованное к libroot.so вызывало исключительно libseveral.a, т.к. libseveral.a это мой форк. Как-то так.

★★★
Ответ на: комментарий от DrBrown

Что бы что-то положить в LD_PRELOAD, нужно это скопировать в систему, а этого нельзя делать по условию.

normann ★★★
() автор топика

Если libseveral.a линкуется с libroot.so, то дефолтно последняя без всяких доп телодвижений будет содержать (и экспортировать) все символы первой. Единственное требование, которое нужно обеспечить - приложуха, которая линкуется с libroot.so должна получать эту либу перед libanother, тогда libroot будет в link map’е раньше и загрузчик будет находить символы в ней.

kvpfs ★★
()
Последнее исправление: kvpfs (всего исправлений: 1)
Ответ на: комментарий от kvpfs

Если libseveral.a линкуется с libroot.so, то дефолтно последняя без всяких доп телодвижений будет содержать все символы первой.

так они экспортроваться должны же. если я влинковал статически либу, разве они будут теперь экспортироваться из моей аппы, да еще в динамике?

alysnix ★★★
()
Ответ на: комментарий от kvpfs

Ещё навскидку скажу про Linker scripts, простые ASCII файлы (например /usr/lib/libgcc_s.so), по идее там можно сделать прокладку с любым функционалом (я их не юзал).

kvpfs ★★
()
Ответ на: комментарий от kvpfs

стоп, ты имеешь виду, что если аппа линкует в себя статическую либу… она будет «экспортировать» ее символы? статическая либа вообще вроде символы не «экспортирует». это просто набор обьектников жеж.

экспорты точно нужны динамической либе, поскольку их будут ковырять в рантайме.

впрочем по линуху я больше юзер

alysnix ★★★
()
Ответ на: комментарий от alysnix

Что есть аппа? Если речь про application, то ему нужно кинуть флаг -rdynamic, тогда из этого бинаря будет торчать всё. Если мы говорим про so’шку, то из неё дефолтно торчит всё.

kvpfs ★★
()

Выкинуть и забыть статическую библиотеку, нужную сошку выбирать через LD_LIBRARY_PATH/LD_PRELOAD.

slovazap ★★★★★
()
Ответ на: комментарий от kvpfs

Если программа просит первую либу, первая либа просит вторую, вторая третью, определяет ли это порядок, в котором они будут находиться в памяти и в котором будет производиться поиск функции? Если да, то каков этот порядок? Есть ли гарантия этого порядка?

normann ★★★
() автор топика
Последнее исправление: normann (всего исправлений: 2)
Ответ на: комментарий от normann

Порядок есть, все подгружаемые либы попадают в link map, положение либ в этой структуре и задаёт порядок в котором будут проштудированы либы. Когда встречается неразрешённый символ, то вызывается ld.so, ему передаются искомый символ и link map, который он штудирует с самого начала. В общих чертах так, но есть ещё всякие детали вроде неймспейсов и опций загрузчику. Оставлю небольшой код, которые печатает link map бинаря в консоль, можете поэкспериментировать передавая разные либы линкеру (и в разном порядке) при компиляции, вызывать dlopen() с разными опциями и смотреть на порядок либ.

     #define _GNU_SOURCE
     #include <link.h>
     #include <dlfcn.h>
     #include <stdio.h>
     int main()
     {
        static char addr_in_mod;
        Dl_info __info;
        struct link_map *lm;
        if(dladdr1(&addr_in_mod, &__info, (void**)&lm, RTLD_DL_LINKMAP) != 0) {
           printf("link_map:\n");
           struct link_map *i = lm;
           for(; i->l_prev != NULL; i = i->l_prev);
           for (; i != NULL; i = i->l_next)
              printf("addr diff=%p  name=%s%s",(void*)i->l_addr,  i->l_name, i==lm?"  <--cur\n":"\n");
        }
     }

Пример выхлопа:

link_map:
addr diff=0x41f000  name=  <--current module
addr diff=0xb7fc4000  name=linux-gate.so.1
addr diff=0xb7fa3000  name=/lib/libdl.so.2
addr diff=0xb7dc5000  name=/lib/libc.so.6
addr diff=0xb7fc6000  name=/lib/ld-linux.so.2
kvpfs ★★
()
Последнее исправление: kvpfs (всего исправлений: 1)
Ответ на: комментарий от normann

Есть ли гарантия этого порядка?

Я таких гарантий не видел (честно говоря и не искал), но если у вас прям всё по-взрослому и ответственность, то как вариант - найти какую-то ненужную функцию в libseveral.so, подменить её в своём форке на функцию, которая возваращает какой-то уникальный id - признак того, что форк в линк мэпе находится раньше. Ну и проверять условие на старте софтины этот id, если неправильный, то падать.

kvpfs ★★
()
Последнее исправление: kvpfs (всего исправлений: 1)
Ответ на: комментарий от kvpfs

Большое спасибо, всё получилось.

normann ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.