2

У меня есть общий объект (a.so), который связан с моим исполняемым myexe. a.so выставил метод get_val(), который использует myexe.Когда файлы .so загружаются Linux?

Теперь, когда a.so будет загружено в адресное пространство процесса myexe? это когда myexe вызывает get_val() API, или когда myexe запускается.

+0

Это конкретная операционная система. Вы в Linux? –

+0

Извините, я забыл о упоминании. Да, я спрашиваю об этом для Linux OS – PAL

+0

Один вопрос за сообщение, пожалуйста.Я удалил Q2 и Q3, используя ссылку Ask Question, чтобы добавить 2 новых сообщения по одному на каждый вопрос. – sashoalm

ответ

2

Там представляют собой два (три) типа библиотек:

  • статические библиотеки (суффикс: .a/.lib), который сам становится частью двоичного кода. Строго говоря, это не вся библиотека, это те объекты из библиотеки, которые необходимы для удовлетворения неразрешенных ссылок.
  • разделяемые (динамические) библиотеки (суффикс: .so/.dll), который в двух вариантах, отличающихся временем библиотека загружается:
    • динамической библиотеки связи, которые являются библиотеки, о которых вы сказали компилятор и компоновщик и которые вы называете статическими библиотеками, но которые не являются частью вашей библиотеки, - они загружаются загрузчиком/компоновщиком (в Linux обычно как часть __main() от libc по телефону dlopen()).
    • библиотека динамической загрузки, которую вы называете dlopen().

(Термины кажутся немного нечеткими, я видел различную литературу, используя различные термины, приведенные выше термины, как я запомнил его, чтобы вспомнить понятия.)

Таким образом, если вы используете a.so без звонка dlopen() самостоятельно, a.so - динамическая библиотека ссылок, поэтому она загружается при запуске программы. В этом случае удаление a.so из системы будет препятствовать запуску вашей программы - она ​​будет загружена, но она не сработает до того, как вызывается main().

Если вы используете a.so с вызовом dlopen() самостоятельно, это полностью под вашим контролем.

На вопросы

Q1: Если вы звоните dlopen() себя, с RTLD_LAZY, то a.so будет загружен при первом нерешенным вызова, которые могут быть решены с помощью a.so производится. Если вы звоните dlopen() самостоятельно, с RTLD_NOW, a.so загружается немедленно, то есть до dlopen(). Если вы не вызываете dlopen() самостоятельно, но дайте libc выполнить работу за вас, a.so будет загружен при запуске программы.

Q2: Вы удаляете a.so. Если вы вызываете dlopen() с RTLD_LAZY и не запускаете код, который нуждается в a.so, программа будет работать счастливо, иначе сигнал будет поднят. Если вы не вызываете dlopen(), но дайте libc выполнить эту работу, программа не запустится успешно.

Q3: Фактически, нет способа загрузить a.so без вызова dlopen() (или что-то подобное, что заменит его). Вопрос только в том, вы сами вызываете dlopen(), или вы позволяете среде (т. Е. libc) выполнять эту работу за вас.

Отказ от ответственности: Я не эксперт в этом вопросе, и некоторые части моего ответа могут быть неправильными. Я проверю те части моего ответа, на которых у меня есть сомнения, например, libc, который вызывает dlopen() или что-то еще, и возможно ли иметь ленивое связывание, даже если вы не используете dlopen() самостоятельно. Я буду обновлять ответ, как только у меня появятся результаты.

+0

большое спасибо. Вы почти ответили на все мои сомнения. Только для читателей я вставляю свой вопрос здесь, когда администратор удалил мои половинные вопросы. Q1. Теперь, когда a.so будет загружен в адресное пространство процесса myexe? это когда myexe вызывает get_val() API или когда myexe запущен. Q2. А теперь предположим условие, при котором myexe не вызывает это API get_val вообще, при этом условии, если я удалю a.so из «/ usr/lib» и попытаюсь запустить myexe, будет ли запускаться myexe? Q3. Есть ли способ загрузить a.so с вызовом dlopen (a.so)? Пожалуйста, объясните, когда нам нужно позвонить в dlopen, чтобы загрузить библиотеку? – PAL

+0

Привет, Кристиан, Еще одно сомнение: как сделать библиотеку a.so как dymanic link libray так что libc позаботится о загрузке его при запуске программы ... – PAL

+1

Многие детали этого ответа, например. когда точно загружается «a.so» или различие между «RTLD_LAZY» и «RTLD_NOW», совершенно неверны. –

0

Я думаю, вы находитесь на Linux/x86-64. Это зависит от ОС.

Как правило, общая библиотека ELF загружается в начале выполнения, на ld-linux.so(8). Практически общая библиотека должна быть position independent code (PIC).

Но это может зависеть, и есть dlopen(3) с флагом RTLD_NOW или RTLD_LAZY

Читать Drepper's paper: How To Write Shared Libraries и x86-64 ABI specification

Вы можете использовать strace(1), чтобы выяснить, что происходит в вашей системе Linux.

Вы можете в принципе динамически загрузить foo.so с помощью mmap(2) и обработать самостоятельно relocations. Я сделал (почти) то, что в предыдущем столетии (для SPARC), и поверьте мне, это утомительная задача.

BTW, dlopen выполнен в GNU libc и в musl-libc. Оба являются свободным программным обеспечением, вы можете изучить их исходный код.

Также читайте Program Library HowTo. Это объясняет некоторые подробности, коротко говоря:

  • компилировать исходные файлы разделяемого объекта в ПОС с помощью

    gcc -Wall -fPIC -O src1.c -o src1.pic.o 
    gcc -Wall -fPIC -O src2.c -o src2.pic.o 
    
  • связать их в общей библиотеке foo.so использованием

    gcc -shared src1.pic.o src2.pic.o -o foo.so 
    
  • используйте полный путь до dlopen, например

     void* dlh = dlopen("./foo.so", RTLD_NOW); 
        if (!dlh) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); 
          exit(EXIT_FAILURE); 
    

Тогда вы могли бы иметь соглашение о том, что ваш foo.so плагин должен иметь функцию подписи

typedef int sayhello_sig_t(const char*); 

, который называется say_hello, и вы получите свой адрес с помощью:

sayhello_sig_t* funptr = dlsym(dlh, "say_hello"); 
    if (!funptr) { 
    fprintf(stderr, 
      "dlsym say_hello failure: %s\n, dlerror(); 
    exit(EXIT_FAILURE); 
    } 
Смежные вопросы