Мой вопрос заключается в том, будет ли код в этих библиотеках выделять память в той же куче, что и основное приложение, или они используют свою собственную кучу?
Если библиотека использует ту же самую malloc/free
в качестве приложения (например, из glibc
) - тогда да, программа и все библиотеки будут использовать одну кучу.
Если библиотека использует mmap
напрямую, она может выделить память, которая не является используемой памятьюсамой программой.
Так, например, некоторая функция в файле .so вызывает malloc, будет ли она использовать тот же диспетчер кучи, что и приложение, или другой?
Если функция из .so вызывает malloc, этот malloc совпадает с malloc, вызываемым из программы.Вы можете увидеть журнал привязки символов в Linux / glibc (> 2.1) с
LD_DEBUG=bindings ./your_program
Да, несколько экземпляров менеджеров кучи (с конфигурацией по умолчанию) не могут сосуществовать, не зная друг о друге (проблемаподдерживает синхронизацию размера кучи, выделенного с помощью brk, между экземплярами).Но возможна конфигурация, когда несколько экземпляров могут сосуществовать.
Большинство классических реализаций malloc (ptmalloc *, dlmalloc и т. Д.) Могут использовать два метода получения памяти из системы: brk
и mmap
,Brk - классическая куча, которая является линейной и может расти или уменьшаться.Mmap позволяет получить много памяти в любом месте;и вы можете вернуть эту память обратно в систему (освободить ее) в любом порядке.
При сборке malloc метод brk можно отключить.Затем malloc будет эмулировать линейную кучу, используя только mmap
s, или даже отключит классическую линейную кучу, и все выделения будут производиться из непрерывных фрагментов mmaped.
Таким образом, некоторые библиотеки могут иметь собственный менеджер памяти, например, malloc
скомпилировано с отключенным brk
или с менеджером памяти не-malloc.Этот менеджер должен иметь имена функций, отличные от malloc
и free
, например malloc1
и free1
, или не должен отображать / экспортировать эти имена в динамический компоновщик.
Кроме того, чтоо глобальных данных в этих общих воспоминаниях.Где это лежит?Я знаю, что для приложения оно находится в сегменте bss и data, но не знаю, где оно находится для этих общих объектных файлов.
Вы должны думать как о программе, так и .so как об ELF-файлах.,Каждый файл ELF имеет «заголовки программы» (readelf -l elf_file
).Способ загрузки данных из ELF в память зависит от типа заголовка программы.Если тип "LOAD
", соответствующая часть файла будет mmap
ed (Sic!) В памяти.Обычно есть 2 сегмента LOAD;первый для кода с флагами R + X (чтение + выполнение), второй для данных с флагами R + W (чтение + запись).Разделы .bss
и .data
(глобальные данные) размещаются в сегменте типа LOAD с флагом разрешения записи.
И в исполняемой, и в общей библиотеке есть сегменты LOAD.У некоторых из сегментов есть memory_size> file_size.Это означает, что сегмент будет расширен в памяти;первая часть будет заполнена данными из ELF-файла, а вторая часть размера (memory_size-file_size) будет заполнена нулями (для *bss
секций), используя mmap(/dev/zero)
и memset(0)
Когда ядро или динамический компоновщик загружает файл ELF в память, они не будут думать о совместном использовании.Например, вы хотите запустить одну и ту же программу дважды.Первый процесс загрузит доступную только для чтения часть файла ELF с помощью mmap;второй процесс будет делать то же самое mmap (если aslr активен - второй mmap будет находиться на другом виртуальном адресе).Задача кэширования страниц (подсистема VFS) - хранить одну копию данных в физической памяти (с помощью COPY-on-WRITE или COW);и mmap просто устанавливает сопоставления из виртуального адреса в каждом процессе в одно физическое местоположение.Если какой-либо процесс изменит страницу памяти;он будет скопирован при записи в уникальную личную физическую память.
Код загрузки находится в glibc/elf/dl-load.c
(_dl_map_object_from_fd
) для ld.so и linux-kernel/fs/binfmt_elf.c
для загрузчика ELF ядра (elf_map
, load_elf_binary
).Выполните поиск для PT_LOAD
.
Итак, глобальные данные и данные bss всегда отображаются в частном порядке в каждом процессе, и они защищены COW.
Куча и стек распределяются во время выполнения с помощью brk + mmap (куча) и автоматически ядром ОС в brk-подобном процессе (для стека основного потока).Стеки дополнительных потоков выделяются с mmap
в pthread_create
.