Кто создает виртуальную память в Linux? - PullRequest
1 голос
/ 20 марта 2012

Я знаю, что ядро ​​заботится о отображении виртуальной памяти в реальную память. Но я хочу знать, кто на самом деле создает виртуальную память для процесса, как показано в файле / proc / pid / maps.

1) Компилятор / компоновщик создает область виртуальной памяти для процесса, а ядро ​​просто отображает ее в реальную память (потому что область виртуальной памяти не имеет значения, и все это имеет значение для отображения)?

2) Или само ядро ​​создает пространство виртуальной памяти при разветвлении процесса и отображает его в реальную память?

Наконец, что делает системный вызов mmap (1) или (2)?

Ответы [ 2 ]

3 голосов
/ 21 марта 2012

Оба ваших утверждения на самом деле верны (в некоторой степени).

В случае исполняемого ELF-файла компоновщик полагается на скрипт компоновщика для назначения адреса в виртуальном пространстве каждому символу программы (они сгруппированы в секции, все из которых имеют начальный адрес и размер). Вы можете увидеть скрипт по умолчанию, который используется, вызывая ld --verbose. Разделы двоичного файла и их адреса можно увидеть с помощью таких инструментов, как readelf или objdump, например, readelf -l /bin/cat. Затем, если вы запустите cat /proc/self/maps, вы должны сопоставить адреса, по которым сопоставлен /bin/cat. Таким образом, системный вызов execve ядра делает это: заменяет адресное пространство текущего процесса новым, в которое отображается исполняемый файл, заданный в качестве аргумента.

Конечно, если бы каждому биту кода был назначен статический адрес, вы столкнулись бы с проблемами с общими библиотеками. Совместно используемые библиотеки используют независимый от позиции код, поэтому их можно отобразить повсюду в адресном пространстве процесса. Здесь ядро ​​принимает решение о том, что делать дальше.

mmap не выполняет ни (1), ни (2), он просто отображает память или часть файла по заданному адресу адресного пространства (или позволяет ядру решить, какой адрес использовать). На самом деле он используется для отображения общих библиотек, которые использует программа. Чтобы увидеть, как, выполните strace /bin/true и посмотрите, как сначала вызывается execve, чтобы создать адресное пространство процесса из двоичного файла, и как открывается файл libc, а соответствующие разделы mmap'ируются с соответствующими правами загрузчиком программы. :

execve("/bin/true", ["/bin/true"], [/* 69 vars */]) = 0
...
open("/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
mmap(NULL, 3804080, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f224f351000
mprotect(0x7f224f4e8000, 2097152, PROT_NONE) = 0
mmap(0x7f224f6e8000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x197000) = 0x7f224f6e8000

Также стоит прочитать следующие статьи:

1 голос
/ 20 марта 2012

Ядро - это сущность, которая на самом деле создает , а управляет областями виртуальной памяти, которые вы видите в / proc / pid / maps.Внутри структуры, содержащей состояние каждого процесса (struct task_struct), есть struct mm_struct (смотрите в linux / sched.h), и, в частности, внутри это struct vm_area_struct * mmap.Это список, поддерживаемый ядром всех областей памяти (называемых дескрипторы областей ), отображенных в адресное пространство процесса.Когда вызывается mmap, в этот список добавляется новый элемент, который впоследствии будет отображаться в / proc / pid / maps.

Обратите внимание, что большинство областей с файловой поддержкой, например libc.so, перечисленных в / proc / pid / maps, отображаются там кодом динамического компоновщика (ld.so) при запуске процесса.

Также обратите внимание, что ядро ​​не будет создавать виртуально-физические отображения для адресов в этих регионах, пока это не станет абсолютно необходимым.

Надеюсь, это поможет

...