Разработка приложений в среде Linux. Второе издание
Шрифт:
Исполняемые файлы можно отображать на память программы, позволяя программе динамически загружать новые исполняемые области. Именно так реализуется динамическая загрузка, описанная в главе 27.
Новую память можно распределить отображением части
Новую память, распределенную посредством карт памяти, можно сделать исполняемой, наполняя ее машинными командами, которые затем запускаются. Это свойство используется оперативными (just-in-time) компиляторами.
85
Хотя большинство устройств символьного ввода-вывода не могут быть отображены,
Файлы могут рассматриваться как память и читаться с использованием указателей, а не системных вызовов. Это существенно упрощает программы, избавляя от необходимости применения вызовов
Отображение в памяти позволяет процессам совместно использовать области памяти, участвующие в создании и уничтожении процесса. Содержимое памяти хранится в отображаемом файле, делая его независимым от процессов.
13.2.1. Выравнивание по страницам
Системная память делится на порции под названием страницы. Размер страницы изменяется в зависимости от архитектуры, и на некоторых процессорах размер страницы может изменяться ядром. Функция
Для каждой страницы системы ядро сообщает оборудованию, каким образом каждый процесс может получить доступ к странице (например, записать, выполнить или не выполнять никаких действий). Когда процесс пытается получить доступ к странице способом, нарушающим ограничения ядра, это вызывает ошибку сегментации (
Адрес памяти должен быть выровнен по страницам, если это адрес начала страницы. Иначе говоря, адрес должен быть целым, кратным размеру страницы архитектуры. В системе со страницами в 4 Кбайт адреса 0, 4 096, 16 384 и 32 768 являются выровненными по страницам (конечно, это далеко не весь список), потому что первая, вторая, пятая и девятая страницы системы начинаются с указанных адресов.
13.2.2. Установка отображения в памяти
Новые карты памяти создаются с помощью системного вызова
Параметр
Второй параметр,
Процесс проверяет, какие типы доступа разрешены новой области памяти. Это должно быть одно или несколько значений из табл. 13.2, объединенных с помощью битового "ИЛИ", либо
86
Ошибка сегментации возникнет при попытке доступа к нераспределенной странице.
Таблица 13.2. Флаги защиты
Флаг | Описание |
---|---|
PROT_READ | Из отображаемой области можно читать. |
PROT_WRITE | В отображаемую область можно записывать. |
PROT_EXEC | Отображаемую область можно выполнять. |
Принудительное применение определенной защиты ограничено аппаратной платформой, на которой работает программа. Во многих архитектурах не разрешено выполнение кода в области памяти, если из нее запрещено чтение. При таком оборудовании отображение области с помощью
По этой причине на флаги защиты памяти, передаваемые в
В
Таблица 13.3. Флаги
Флаг | POSIX? | Описание |
---|---|---|
MAP_ANONYMOUS | Да | Игнорировать fd , создать анонимную карту. |
MAP_FIXED | Да | Сбой
address ). |
MAP_PRIVATE | Да | Запись приватна для процесса. |
MAP_SHARED | Да | Запись копируется в файл. |
MAP_DENYWRIТЕ | Нет | Не разрешать нормальную запись в файл. |
MAP_GROWSDOWN | Нет | Расширить область памяти сверху вниз. |
MAP_LOCKED | Нет | Блокировать страницы в памяти. |
MAP_ANONYMOUS | Вместо отображения файла возвращается анонимное отображение. Оно ведет себя подобно обычному отображению, но без участия физического файла. Хотя эту область памяти нельзя ни использовать совместно с другими процессами, ни автоматически сохранять в файле, анонимное отображение позволяет процессам распределять новую память для индивидуального использования. Такое отображение часто применяется реализациями malloc , а также еще несколькими специализированными приложениями. Параметр fd игнорируется при использовании этого флага. |
MAP_FIXED | Если карту нельзя поместить по запрашиваемому адресу, mmap завершается неудачей. Если этот флаг не определен, ядро попытается разместить карту по указанному адресу, но если это не удастся, то отобразит ее на альтернативный адрес. Если адрес, переданный в address , уже использовался mmap , элемент, отображаемый в этой области, будет замещен новой картой памяти. Это означает, что лучше передавать только те адреса, которые были возвращены предыдущими вызовами в mmap ; если применяются произвольные адреса, может быть перезаписана область памяти, используемая системными библиотеками. |
MAP_PRIVATE | Модификации области памяти должны быть индивидуальными для процесса. Их не следует совместно использовать с другими процессами, которые отображают этот же файл (процессами, отличающимися от связанных процессов, которые ответвляются после создания карты памяти), а также отражать в самом файле. Должен использоваться флаг MAP_SHARED или MAP_PRIVATE . Если область памяти незаписываемая, тип используемого флага не имеет значения. |
MAP_SHARED | Изменения в области памяти копируются обратно в файл, который был отображен и использован совместно с другими процессами, отображающими этот же файл. (Для записи изменений в область памяти следует установить PROT_WRITE ; иначе область памяти будет постоянной). Должен использоваться флаг MAP_SHARED или MAP_PRIVATE . |
MAP_DENYWRITE | Обычно системные вызовы для нормального доступа к файлам (например, write ) могут модифицировать отображенный файл. Однако если область запускается, это будет не самым лучшим решением. Указание MAP_DENYWRITE приводит к тому, что операции записи файлов, отличные от тех, что совершаются через карту памяти, будут возвращать etxtbsy . |
MAP_GROWSDOWN | Попытка немедленного доступа к памяти, расположенной непосредственно перед отображаемой областью, обычно вызывает SIGSEGV . Этот флаг заставляет ядро расширять область для младших адресов памяти по страницам, если процесс пытается получить доступ к памяти на младшей смежной странице, и продолжает процесс обычным образом. Это разрешает ядру автоматически расширять стеки процессов на платформах, на которых стеки расширяются сверху вниз (наиболее распространенный случай). Это специфичный для платформы флаг, применяемый обычно только для системного кода. Единственным ограничением для MAP_GROWSDOWN является ограничение размеров стека, рассматриваемое в главе 10. Если ограничение не установлено, ядро расширит отображенный сегмент, несмотря на то, выгодно ли это. Однако оно не будет расширять сегмент поверх остальных отображаемых областей. |
MAP_GROWSUP | Этот флаг работает так же, как и MAP_GROWSDOWN , но предназначен для тех редких платформ, на которых стеки расширяются снизу вверх, что означает расширение области со старших, а не младших адресов. (В ядре версии 2.6.7 только архитектура parisc имеет стеки, расширяющиеся снизу вверх.) Как и MAP_GROWSDOWN , этот флаг зарезервирован для системного кода с установленным ограничением на размер стека. |
MAP_LOCKED | Область блокируется в памяти. Это означает, что она никогда не будет подлежать страничному обмену. Это важно для систем реального времени ( mlock , рассматриваемый далее в этой главе, предоставляет еще один метод блокирования памяти). Обычно это может установить только привилегированный пользователь; обычным пользователям не разрешено блокировать страницы в памяти. Некоторые системы Linux допускают ограниченное распределение заблокированной памяти непривилегированными пользователями, и эта возможность, вероятно, вскоре будет добавлена к стандартному ядру Linux. |