Вопрос A
Вы можете заменить библиотеку во время ее использования приложением, если вы сделаете это правильно.
Прежде чем мы туда доберемся, давайте посмотримпосмотрите на основной двоичный файл программы.Вот пример программы:
#include <unistd.h>
void justsit(void) {
for (;;) {
sleep(1);
}
}
int main(int argc, char **argv) {
printf("My PID is %d\n", getpid());
justsit();
return 0;
}
Скомпилируйте и запустите ее:
$ gcc -Wall -o example example.c
$ ./example
My PID is 4339
Теперь она просто будет сидеть там, поэтому откройте новый терминал, чтобы сделать это:
$ gcc -Wall -o example-updated example.c
$ cp example-updated example
cp: cannot create regular file `example': Text file busy
Что случилось сейчас?Ядро отказалось изменить файл пример , поскольку у него есть процесс, который запускает этот файл.
Теперь давайте попробуем удалить его:
$ rm example
Что?Что сработало?Почему файл можно удалить, но не заменить?Да, или, скорее, файл не был действительно удален, просто «имя», ядро сообщает файловой системе, чтобы сохранить содержимое файла.Если файл больше не открыт, содержимое также удаляется.( dentry удаляется немедленно, но inode освобождается, когда у него нет пользователей, как сказали бы люди из файловой системы)
Это можно увидеть в / proc: (Вот почему программа печатает свой PID, чтобы вы могли легко проверить это)
$ readlink /proc/4339/exe
/tmp/t/example (deleted)
Во всяком случае.Тот факт, что он работает так, означает, что можно безопасно обновить программу, удалив старый двоичный файл и поместив новый в то же место.Для этого есть программа: install (1).
Хорошо, вернемся к вашему вопросу - общие объекты.
Давайте разберем пример на две части, main.c и shared.c:
/* main.c */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void justsit(void);
int main(int argc, char **argv) {
printf("My PID is %d\n", getpid());
justsit();
return 0;
}
и
/* shared.c */
#include <stdio.h>
#include <unistd.h>
void justsit(void) {
for (;;) {
sleep(1);
}
}
Скомпилируйте их так:
$ gcc -Wall --shared -o libshared.so shared.c
$ gcc -Wall -L. -o main main.c -lshared
Теперь, надеюсь, если мы попытаемся заменить libshared.so, мы получим подобное "Текстовый файл занят "ошибка?Посмотрим.Сначала запустите основную программу - текущий каталог не находится в пути поиска lib, поэтому скажите динамическому компоновщику искать там:
$ LD_LIBRARY_PATH=. ./main
My PID is 5697
Перейдите на другой терминал и замените библиотеку чем-то явно неработающим:
$ echo "junk" > libshared.so
$
Во-первых - не было отказано, как замена двоичного файла программы.А в другом терминале произошло что-то интересное, программа перестала работать со следующим сообщением об ошибке:
Segmentation fault
$
Поэтому НЕ ЗАМЕНЯЕТСЯ заменить библиотеку, используемую программой!Но, как видно из приведенного выше примера, это может иметь катастрофические последствия.
К счастью, тот же «трюк», который использовался для замены работающего двоичного файла, можно использовать для замены используемой библиотеки.Перезапустите основную программу (не забудьте также перекомпилировать libshared.so, поскольку она была заменена нежелательной) и посмотрите, насколько безопасно выполнять rm в библиотеке./ proc / PID / maps можно проверить, какие общие объекты использует процесс:
$ cat /proc/5733/maps | grep libshared.so
008a8000-008a9000 r-xp 00000000 08:01 2097292 /tmp/t/libshared.so
008a9000-008aa000 r--p 00000000 08:01 2097292 /tmp/t/libshared.so
008aa000-008ab000 rw-p 00001000 08:01 2097292 /tmp/t/libshared.so
$ rm libshared.so
$ cat /proc/5733/maps | grep libshared.so
008a8000-008a9000 r-xp 00000000 08:01 2097292 /tmp/t/libshared.so (deleted)
008a9000-008aa000 r--p 00000000 08:01 2097292 /tmp/t/libshared.so (deleted)
008aa000-008ab000 rw-p 00001000 08:01 2097292 /tmp/t/libshared.so (deleted)
Основная программа продолжает работать нормально.Опять же, это потому, что с диска было удалено только имя (dentry), а не фактическое содержимое (inode).После удаления можно безопасно создать новый файл с именем libshared.so, не затрагивая работающую программу.
Итак, подведем итог - просто используйте команду install для установки программ и двоичных файлов.
Вопрос B
Да, распечатывается динамическим компоновщиком в пользовательском пространстве.
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
execl("./main", "main", NULL);
printf("exec failed?\n");
return 0;
}
Скомпилируйте его с помощью gcc -Wall -o execit execit.c
.Помните, что execl
заменяет текущий процесс указанной командой.
$ ./execit
main: error while loading shared libraries: libshared.so: cannot open shared object file: No such file or directory
$ rm main
$ ./execit
exec failed?
Что произошло и что это нам говорит?Сначала есть error while loading shared libraries
без exec failed?
.Никакой «сбой exec» не предполагает, что процесс был успешно заменен.Это означает, что ядро передало управление динамическому компоновщику, который вышел из строя.После удаления «main» он рано выходит из строя и процесс не заменяется.