2012-03-20 2 views
1

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

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

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

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

ответ

1

Ядро является сущностью, которая на самом деле создает и управляет регионов виртуальной памяти, которые вы видите в/Proc/PID/карты. В структуре, содержащей состояние каждого процесса (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) при запуске процесса.

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

Надеется, что это помогает

3

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

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

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

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

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 

следующие статьи также могут быть стоит прочитать:

Смежные вопросы