Відповіді:
dlopenце не системний виклик, це функція бібліотеки в бібліотеці libdl . У системі відображаються лише системні дзвінки strace.
На Linux та на багатьох інших платформах (особливо на тих, які використовують формат ELF для виконуваних файлів), dlopenреалізується шляхом відкриття цільової бібліотеки open()та відображення її в пам'яті mmap(). mmap()насправді важлива частина тут, це те, що включає в себе бібліотеку в адресний простір процесу, щоб процесор міг виконувати свій код. Але ви маєте до open()файлу, перш ніж зможете mmap()!
ld-linuxядро відображається у складі execveсистемного виклику.
dlopen не має нічого спільного з спільними бібліотеками, як ви думаєте про них. Існує два способи завантаження спільного об’єкта:
mainфункції та встановити процесний простір програми, щоб програма знайшла функції бібліотеки. Це включає open()в себе лубрарій, а потім mmap()його, після чого слід встановити кілька таблиць пошуку.libdl, з якого ви потім (використовуючи перший метод) можете викликати dlopen()іdlsym()функції. За допомогою dlopen ви отримуєте ручку до бібліотеки, яку потім можете використовувати за допомогою dlsym для отримання покажчика функції на певну функцію. Цей метод набагато складніший для програміста, ніж перший метод (оскільки вам доведеться робити налаштування вручну, а не змусити лінкер зробити це автоматично для вас), а також він є більш крихким (оскільки ви не отримуєте компіляцію -час перевіряє, що ви викликаєте функції з правильними типами аргументів, як ви отримуєте в першому методі), але перевага полягає в тому, що ви можете вирішити, який спільний об’єкт завантажувати під час виконання (або навіть взагалі завантажувати його), роблячи цей інтерфейс призначений для функціональності типу плагінів. Нарешті, інтерфейс dlopen також менш портативний, ніж інший спосіб, оскільки його механіка залежить від точної реалізації динамічного лінкера (звідси libtool'slibltdl, який намагається абстрагувати ці відмінності).Сьогодні більшість операційних систем використовують метод спільних бібліотек, запроваджений наприкінці 1987 року SunOS-4.0. Цей метод заснований на відображенні пам'яті через mmap ().
Зважаючи на той факт, що на початку 1990-х компанія Sun навіть пожертвувала старий код на основі a.out (Solaris в той час вже базувався на ELF) людям FreeBSD і що цей код згодом був переданий багатьом іншим системам (включаючи Linux) Ви можете зрозуміти, чому немає великої різниці між платформами.
ltrace -Sаналіз мінімального прикладу показує, що mmapвикористовується в glibc 2.23
У glibc 2.23, Ubuntu 16.04, працює latrace -Sна мінімальній програмі, яка використовує dlopen:
ltrace -S ./dlopen.out
показує:
dlopen("libcirosantilli_ab.so", 1 <unfinished ...>
SYS_open("./x86_64/libcirosantilli_ab.so", 524288, 06267650550) = -2
SYS_open("./libcirosantilli_ab.so", 524288, 06267650550) = 3
SYS_read(3, "\177ELF\002\001\001", 832) = 832
SYS_brk(0) = 0x244c000
SYS_brk(0x246d000) = 0x246d000
SYS_fstat(3, 0x7fff42f9ce30) = 0
SYS_getcwd("/home/ciro/bak/git/cpp-cheat"..., 128) = 54
SYS_mmap(0, 0x201028, 5, 2050) = 0x7f1c323fe000
SYS_mprotect(0x7f1c323ff000, 2093056, 0) = 0
SYS_mmap(0x7f1c325fe000, 8192, 3, 2066) = 0x7f1c325fe000
SYS_close(3) = 0
SYS_mprotect(0x7f1c325fe000, 4096, 1) = 0
тому ми відразу бачимо, що dlopenдзвінки open+ mmap.
Дивовижний ltraceінструмент відстежує як виклики бібліотеки, так і системні виклики, і тому ідеально підходить для вивчення того, що відбувається в даному випадку.
Більш детальний аналіз показує, що openповертає дескриптор файлу 3(наступний вільний після stdin, out та err).
readпотім використовує цей дескриптор файлів, але TODO, чому mmapаргументи обмежені чотирма, і ми не можемо побачити, який fd там використовувався, оскільки це 5-й аргумент . straceпідтверджує, як очікувалося, 3це один, і порядок Всесвіту відновлюється.
Хоробрі душі також можуть вписатись у код glibc, але я не зміг знайти mmapпісля швидкого грепу і я лінивий.
Випробуваний на цьому мінімальному прикладі з побудовою котлопластину на GitHub .
straceзвіти про системні виклики (тобто функції, реалізовані безпосередньо ядром). Динамічні бібліотеки не є функцією ядра; dlopenє частиною бібліотеки С, а не ядром. Реалізація dlopenвиклику call open(який є системним викликом) для відкриття бібліотечного файлу, щоб його можна було прочитати.
ltrace.
ltrace -Sідеально аналізує це, оскільки він також показує системні дзвінки