Используют ли общие библиотеки ту же кучу, что и приложение?

Скажем, у меня есть приложение в Linux, которое использует разделяемые библиотеки (.so files). Мой вопрос заключается в том, будет ли код в этих библиотеках выделять память в той же куче, что и основное приложение, или они используют свою собственную кучу?

Так, например, некоторая функция в файле .so вызывает malloc, будет ли она использовать тот же кучный менеджер, что и приложение или другое? Кроме того, как насчет глобальных данных в этих общих воспоминаниях. Где он лежит? Я знаю, что приложение лежит в сегменте bss и данных, но не знает, где это для этих общих файлов объектов.

Ответы

Ответ 1

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

Если библиотека использует тот же 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 или даже отключит классическую линейную кучу, и все распределения будут сделаны из несмежных mmaped fragmens.

Итак, некоторые библиотеки могут иметь собственный менеджер памяти, например. malloc скомпилирован с brk отключен или с менеджером памяти не-malloc. Этот менеджер должен иметь имена функций, отличные от malloc и free, например malloc1 и free1, или не должен показывать/экспортировать эти имена в динамический компоновщик.

Также, как насчет глобальных данных в этих общих памяти. Где он лежит? Я знаю, что приложение лежит в сегменте bss и данных, но не знает, где это для этих общих файлов объектов.

Вы должны думать как о программе, так и о файлах ELF. Каждый файл ELF имеет "заголовки программ" (readelf -l elf_file). Способ загрузки данных из ELF в память зависит от типа заголовка программы. Если тип "LOAD", соответствующая часть файла будет конфиденциально mmap ed (Sic!) В память. Обычно имеется 2 сегмента LOAD; первый для кода с флагами R + X (read + execute), а второй - для данных с флагами R + W (чтение + запись). Обе секции .bss и .data (глобальные данные) помещаются в сегмент типа LOAD с флажком с поддержкой записи.

В обеих исполняемых и разделяемых библиотеках есть сегменты LOAD. Некоторые сегменты имеют memory_size > file_size. Это означает, что сегмент будет расширен в памяти; первая часть будет заполнена данными из файла ELF, а вторая часть размера (memory_size-file_size) будет заполнена нулем (для разделов *bss), используя mmap(/dev/zero) и memset(0)

Когда Kernel или Dynamic компоновщик загружает ELF файл в память, они не будут думать о совместном использовании. Например, вы хотите запустить ту же программу дважды. Первый процесс будет загружать часть файла ELF только для чтения с помощью mmap; второй процесс будет делать тот же mmap (если aslr активен - второй mmap будет в другом виртуальном адресе). Задача кэша страниц (подсистема VFS) хранить одну копию данных в физической памяти (с COPY-on-WRITE aka 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.

Ответ 2

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