45.2. Напишите программы, подтверждающие доставку сигналов SIGBUS и SIGSEGV в обстоятельствах, описанных в подразделе 45.4.3.
45.3. Напишите программу, которая использует методику MAP_FIXED, описанную в разделе 45.10, для создания нелинейного отображения, аналогичного показанному на рис. 45.5.
46. Операции с виртуальной памятью
Эта глава посвящена системным вызовам, предназначенным для выполнения различных операций с виртуальным адресным пространством процесса:
• системный вызов mprotect() изменяет защиту участка виртуальной памяти;
• системные вызовы mlock() и mlockall() «запирают» участок виртуального пространства в рамках физической памяти и не дают сбросить его на диск;
• системный вызов mincore() позволяет процессу определять, находятся ли страницы виртуального пространства в физической памяти;
• системный вызов madvise() дает возможность сообщить ядру о потенциальной модели поведения процесса в контексте использования участка виртуальной памяти.
Некоторые из этих системных вызовов могут быть особенно полезны в сочетании с участками разделяемой памяти (см. главы 45 и 50), но вы можете применять их для работы с любыми сегментами виртуального адресного пространства.
Методики, описанные в данной главе, на самом деле не имеют никакого отношения к межпроцессному взаимодействию; я включил их в эту часть книги, поскольку они иногда используются вместе с разделяемой памятью.
Системный вызов mprotect() изменяет защиту страниц виртуальной памяти в диапазоне длиной length байт, который начинается с адреса addr.
#include
int mprotect(void *
Возвращает 0 при успешном завершении или -1 при ошибке
Значение, переданное в аргументе addr, должно быть кратным размеру страницы памяти в системе (который возвращается вызовом sysconf(_SC_PAGESIZE)). Стандарт SUSv3 гласит, что аргумент addr
Аргумент prot представляет собой битовую маску, задающую новую защиту для данного участка памяти. Он должен быть равен либо PROT_NONE, либо сочетанию значений PROT_READ, PROT_WRITE и PROT_EXEC, к которым применено побитовое ИЛИ. Все эти флаги имеют то же значение, что и в вызове mmap() (табл. 45.2).
Если процесс попытается обратиться к участку памяти, нарушив заданную защиту, то ядро пошлет ему сигнал SIGSEGV.
Вызов mprotect() позволяет изменить защиту участка отображенной памяти, заданную с помощью mmap(), как показано в листинге 46.1. Эта программа создает анонимное отображение, любой доступ к которому изначально закрыт (PROT_NONE). Затем она открывает доступ для чтения и записи. Прежде чем выполнить данное изменение, программа использует вызов system(), чтобы запустить консольную команду, выводящую строчку из файла /proc/PID/maps, относящуюся к отображенному участку. Это позволит увидеть, как изменилась защита памяти (ту же информацию можно получить, вручную разобрав файл /proc/self/maps, но вызов system() позволяет сократить код программы). Запустив данное приложение, мы увидим следующее:
$ ./t_mprotect
Before mprotect()
b7cde000-b7dde000 —s 00000000 00:04 18258 /dev/zero (deleted)
After mprotect()
b7cde000-b7dde000 rw-s 00000000 00:04 18258 /dev/zero (deleted)
Последняя строка вывода говорит о том, что вызов mprotect() изменил права доступа к участку памяти на PROT_READ | PROT_WRITE.
Листинг 46.1. Изменение защиты памяти с помощью вызова mprotect()
vmem/t_mprotect.c
#define _BSD_SOURCE /* Получаем определение MAP_ANONYMOUS из
#include
#include "tlpi_hdr.h"
#define LEN (1024 * 1024)
#define SHELL_FMT "cat /proc/%ld/maps | grep zero"
#define CMD_SIZE (sizeof(SHELL_FMT) + 20)
/* Выделяем дополнительное место для строки с целым числом */
int
main(int argc, char *argv[])
{
char cmd[CMD_SIZE];
char *addr;
/* Создаем анонимное отображение с полным отсутствием доступа */
addr = mmap(NULL, LEN, PROT_NONE, MAP_SHARED | MAP_ANONYMOUS, — 1, 0);
if (addr == MAP_FAILED)
errExit("mmap");
/* Выводим строку из /proc/self/maps, относящуюся к отображению */
printf("Before mprotect()\n");
snprintf(cmd, CMD_SIZE, SHELL_FMT, (long) getpid());
system(cmd);
/* Изменяем защиту памяти, разрешая чтение и запись */
if (mprotect(addr, LEN, PROT_READ | PROT_WRITE) == -1)
errExit("mprotect");
printf("After mprotect()\n");
system(cmd); /* Проверяем защиту, считывая файл /proc/self/maps */
exit(EXIT_SUCCESS);
}
vmem/t_mprotect.c