NOM¶
mmap, munmap - Établir/supprimer une projection en mémoire
(map/unmap) des fichiers ou des périphériques
SYNOPSIS¶
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
int munmap(void *addr, size_t length);
Consultez la section NOTES pour plus d'informations sur les exigences de la
macro de test de fonctionnalité.
DESCRIPTION¶
mmap() crée une nouvelle projection dans l'espace d'adressage
virtuel du processus appelant. L'adresse de démarrage de la nouvelle
projection est indiquée dans
addr. Le paramètre
length indique la longueur de la projection.
Si
addr est NULL, le noyau choisit l'adresse à laquelle
démarrer la projection ; c'est la méthode la plus
portable pour créer une nouvelle projection. Si
addr n'est pas
NULL, le noyau le considère comme une indication sur l'endroit
où placer la projection ; sous Linux, elle sera placée
à une frontière de page proche. L'adresse de la nouvelle
projection est renvoyée comme résultat de l'appel.
Le contenu d'une projection de fichier (par opposition à une projection
anonyme ; voir ci-dessous
MAP_ANONYMOUS) est initialisé
avec
length octets à partir de la position
offset dans le
fichier (ou autre objet) correspondant au descripteur de fichier
fd.
offset doit être un multiple de la taille de page,
renvoyée par
sysconf(_SC_PAGE_SIZE).
L'argument
prot indique la protection que l'on désire pour cette
zone de mémoire, et ne doit pas entrer en conflit avec le mode
d'ouverture du fichier. Il s'agit soit de
PROT_NONE (le contenu de la
mémoire est inaccessible) soit d'un OU binaire entre les constantes
suivantes :
- PROT_EXEC
- On peut exécuter du code dans la zone mémoire.
- PROT_READ
- On peut lire le contenu de la zone mémoire.
- PROT_WRITE
- On peut écrire dans la zone mémoire.
- PROT_NONE
- Les pages ne peuvent pas être accédées.
Le paramètre
flags détermine si les modifications de la
projection sont visibles depuis les autres processus projetant la même
région, et si les modifications sont appliquées au fichier
sous-jacent. Ce comportement est déterminé en incluant
exactement une des valeurs suivantes dans
flags :
- MAP_SHARED
- Partager la projection. Les modifications de la projection sont visibles
dans les autres processus qui projettent ce fichier, et sont
appliquées au fichier sous-jacent. En revanche, ce dernier n'est
pas nécessairement mis à jour tant qu'on n'a pas
appelé msync(2) ou munmap().
- MAP_PRIVATE
- Créer une projection privée, utilisant la méthode de
copie à l'écriture. Les modifications de la projection ne
sont pas visibles depuis les autres processus projetant le même
fichier, et ne modifient pas le fichier lui-même. Il n'est pas
précisé si les changements effectués dans le fichier
après l'appel mmap() seront visibles.
Ces deux attributs sont décrits dans POSIX.1-2001.
De plus, zéro ou plus des valeurs suivantes peuvent être incluses
dans
flags (avec un OU binaire) :
- MAP_32BIT (depuis Linux 2.4.20, 2.6)
- Placer la projection dans les deux premiers gigaoctets de l'espace
d'adressage du processus. Cet attribut n'est pris en charge que sous
x86-64, pour les programmes 64 bits. Il a été
ajouté pour permettre à la pile d'un thread d'être
allouée dans les deux premiers gigaoctets de mémoire, afin
d'améliorer les performances des changements de contexte sur les
premiers processeurs 64 bits. Les processeurs x86-64 modernes n'ont
plus ces problèmes de performance, donc l'utilisation de cet
attribut n'est pas nécessaire sur ces systèmes. L'attribut
MAP_32BIT est ignoré quand MAP_FIXED est
positionné.
- MAP_ANON
- Synonyme de MAP_ANONYMOUS. Déconseillé.
- MAP_ANONYMOUS
- La projection n'est supportée par aucun fichier ; son
contenu est initialisé à 0. Les arguments fd et
offset sont ignorés ; cependant, certaines
implémentations demandent que fd soit -1 si
MAP_ANONYMOUS (ou MAP_ANON) est utilisé, et les
applications portables doivent donc s'en assurer. Cet attribut,
utilisé en conjonction de MAP_SHARED, n'est
implémenté que depuis Linux 2.4.
- MAP_DENYWRITE
- Cet attribut est ignoré. (Autrefois, une tentative
d'écriture dans le fichier sous‐jacent échouait avec
l'erreur ETXTBUSY. Mais ceci permettait des attaques par
déni de service.)
- MAP_EXECUTABLE
- Cet attribut est ignoré.
- MAP_FILE
- Attribut pour compatibilité. Ignoré.
- MAP_FIXED
- Ne pas considérer addr comme une indication :
n'utiliser que l'adresse indiquée. addr doit être un
multiple de la taille de page. Si la zone mémoire indiquée
par addr et len recouvre des pages d'une projection
existante, la partie recouverte de la projection existante sera
ignorée. Si l'adresse indiquée ne peut être
utilisée, mmap() échouera. Il est
déconseillé d'utiliser cette option, car requérir une
adresse fixe pour une projection n'est pas portable.
- MAP_GROWSDOWN
- Utilisé pour les piles. Indique au système de gestion de la
mémoire virtuelle que la projection doit s'étendre en
croissant vers le bas de la mémoire.
- MAP_HUGETLB (depuis Linux 2.6.32)
- Allouer la projection à l'aide de « pages
immenses ». Consultez le fichier source du noyau Linux
Documentation/vm/hugetlbpage.txt pour plus d'informations.
- MAP_LOCKED (depuis Linux 2.5.37)
- Verrouille la page projetée en mémoire à la
manière de mlock(2). Cet attribut est ignoré sur les
noyaux plus anciens.
- MAP_NONBLOCK (depuis Linux 2.5.46)
- N'a de sens qu'en conjonction avec MAP_POPULATE. Ne pas effectuer
de lecture anticipée : créer seulement les
entrées de tables de page pour les pages déjà
présentes en RAM. Depuis Linux 2.6.23, cet attribut fait que
MAP_POPULATE n'a aucun effet. Un jour la combinaison de
MAP_POPULATE et MAP_NONBLOCK pourra être
implémentée de nouveau.
- MAP_NORESERVE
- Ne pas réserver d'espace de swap pour les pages de cette
projection. Une telle réservation garantit que l'on puisse modifier
les zones soumises à une copie-en-écriture. Sans
réservation, on peut recevoir un signal SIGSEGV durant une
écriture, s'il n'y a plus de place disponible. Consultez
également la description du fichier
/proc/sys/vm/overcommit_memory dans la page proc(5). Dans
les noyaux antérieurs à 2.6, cet attribut n'avait d'effet
que pour les projections privées modifiables.
- MAP_POPULATE (depuis Linux 2.5.46)
- Remplit les tables de pages pour une projection. Pour une projection de
fichier, ceci s'effectue par une lecture anticipée du fichier. Les
accès ultérieurs à la projection ne seront pas
bloqués par des fautes de pages. MAP_POPULATE n'est
géré pour les projections privées que depuis
Linux 2.6.23.
- MAP_STACK (depuis Linux 2.6.27)
- Alloue la projection à une adresse qui convient pour la pile d'un
processus ou d'un thread. Cet attribut n'a pour l'instant aucun effet,
mais est utilisé par l'implémentation des threads de la
glibc de telle sorte que si certaines architectures nécessitent un
traitement particulier pour l'allocation de la pile, leur prise en charge
par la suite par la glibc pourra être implémentée de
façon transparente.
- MAP_UNINITIALIZED (depuis Linux 2.6.33)
- N'efface pas les pages anonymes. Cet attribut n'a pour l'instant un effet
que si le noyau a été configuré avec l'option
CONFIG_MMAP_ALLOW_UNINITIALIZED. À cause des implications
sur la sécurité, cette option n'est normalement active que
sur des périphériques embarqués (c'est-à-dire
avec des périphériques avec lesquels il est possible d'avoir
un contrôle total de la mémoire utilisateur).
Parmi les attributs ci-dessus, seul
MAP_FIXED est spécifié
dans POSIX.1-2001. Cependant, la plupart des systèmes gèrent
aussi
MAP_ANONYMOUS (ou son synonyme
MAP_ANON).
Certains systèmes utilisent les attributs supplémentaires
MAP_AUTOGROW,
MAP_AUTORESRV,
MAP_COPY et
MAP_LOCAL.
La mémoire obtenue par
mmap est préservée au travers
d'un
fork(2), avec les mêmes attributs.
La projection doit avoir une taille multiple de celle des pages. Pour un fichier
dont la longueur n'est pas un multiple de la taille de page, la mémoire
restante est remplie de zéros lors de la projection, et les
écritures dans cette zone n'affectent pas le fichier. Les effets de la
modification de la taille du fichier sous‐jacent sur les pages
correspondant aux zones ajoutées ou supprimées ne sont pas
précisés.
munmap()¶
L'appel système
munmap() détruit la projection dans la zone
de mémoire spécifiée, et s'arrange pour que toute
référence ultérieure à cette zone mémoire
déclenche une erreur d'adressage. La projection est aussi
automatiquement détruite lorsque le processus se termine. À
l'inverse, la fermeture du descripteur de fichier ne supprime pas la
projection.
L'adresse
addr doit être un multiple de la taille de page. Toutes
les pages contenant une partie de l'intervalle indiqué sont
libérées, et tout accès ultérieur
déclenchera
SIGSEGV. Aucune erreur n'est détectée
si l'intervalle indiqué ne contient pas de page projetée.
Modifications d'horodatage pour les projections supportées par un fichier¶
Pour les projections supportées par un fichier, le champ
st_atime
du fichier peut être mis à jour à tout moment entre
l'appel
mmap() et le
munmap() correspondant. Le premier
accès dans la page projetée mettra le champ à jour si
cela n'a pas été déjà fait.
Les champs
st_ctime et
st_mtime pour un fichier projeté
avec
PROT_WRITE et
MAP_SHARED seront mis à jour
après une écriture dans la région projetée, et
avant l'éventuel
msync(2) suivant avec attribut
MS_SYNC
ou
MS_ASYNC.
VALEUR RENVOYÉE¶
mmap() renvoie un pointeur sur la zone de mémoire, s'il
réussit. En cas d'échec il retourne la valeur
MAP_FAILED
(c.‐à‐d.
(void *) -1) et
errno contient le code d'erreur.
munmap() renvoie 0 s'il
réussit. En cas d'échec, -1 est renvoyé et
errno
contient le code d'erreur (probablement
EINVAL).
ERREURS¶
- EACCES
- Le descripteur ne correspond pas à un fichier normal, ou on demande
une projection de fichier mais fd n'est pas ouvert en lecture, ou
on demande une projection partagée MAP_SHARED avec
protection PROT_WRITE, mais fd n'est pas ouvert en lecture
et écriture ( O_RDWR). Ou encore PROT_WRITE est
demandé, mais le fichier est ouvert en ajout seulement.
- EAGAIN
- Le fichier est verrouillé, ou trop de pages ont été
verrouillées en mémoire (consultez
setrlimit(2)).
- EBADF
- fd n'est pas un descripteur de fichier valable (et
MAP_ANONYMOUS n'était pas précisé).
- EINVAL
- addr ou length ou offset sont invalides (par
exemple : zone trop grande, ou non alignée sur une
frontière de page).
- EINVAL
- (depuis Linux 2.6.12) length est nul.
- EINVAL
- flags ne contient ni MAP_PRIVATE ni MAP_SHARED, ou
les contient tous les deux.
- ENFILE
- La limite du nombre total de fichiers ouverts sur le système a
été atteinte.
- ENODEV
- Le système de fichiers sous‐jacent ne supporte pas la
projection en mémoire.
- ENOMEM
- Pas assez de mémoire, ou le nombre maximal de projections par
processus a été dépassé.
- EPERM
- L'argument prot a demandé PROT_EXEC mais la zone
appartient à un fichier sur un système de fichiers
monté sans permission d'exécution.
- ETXTBSY
- MAP_DENYWRITE a été réclamé mais
fd est ouvert en écriture.
- EOVERFLOW
- Sur architecture 32 bits avec l'extension de fichiers très
grands (c'est-à-dire utilisant un off_t sur
64 bits) : le nombre de pages utilisées pour
length plus le nombre de pages utilisées pour offset
dépasserait unsigned long (32 bits).
L'accès à une zone de projection peut déclencher les
signaux suivants :
- SIGSEGV
- Tentative d'écriture dans une zone en lecture seule.
- SIGBUS
- Tentative d'accès à une portion de la zone qui ne correspond
pas au fichier (par exemple après la fin du fichier, y compris
lorsqu'un autre processus l'a tronqué).
SVr4, BSD 4.4, POSIX.1-2001.
DISPONIBILITɶ
Sur les systèmes POSIX sur lesquels
mmap(),
msync(2) et
munmap() sont disponibles, la constante symbolique
_POSIX_MAPPED_FILES est définie dans
<unistd.h>
comme étant une valeur supérieure à 0. (Consultez aussi
sysconf(3).)
NOTES¶
Cette page décrit l'interface fournie par la fonction
mmap() de la
glibc. Initialement, cette fonction appelait un appel système du
même nom. Depuis le noyau 2.4, cet appel système a
été remplacé par
mmap2(2). De nos jours, la
fonction
mmap() de la glibc appelle
mmap2(2) avec la bonne
valeur pour
offset.
Sur certaines architectures matérielles (par exemple, i386),
PROT_WRITE implique
PROT_READ. Cela dépend de
l'architecture si
PROT_READ implique
PROT_EXEC ou non. Les
programmes portables doivent toujours indiquer
PROT_EXEC s'ils veulent
exécuter du code dans la projection.
La manière portable de créer une projection est de
spécifier
addr à 0 (NULL), et d'omettre
MAP_FIXED
dans
flags. Dans ce cas, le système choisit l'adresse de la
projection ; l'adresse est choisie de manière à ne pas
entrer en conflit avec une projection existante et de ne pas être
nulle. Si l'attribut
MAP_FIXED est indiqué et si
addr
vaut 0 (NULL), l'adresse projetée sera zéro (NULL).
Certaines constantes de
flags sont définies seulement si
_BSD_SOURCE ou
_SVID_SOURCE est défini. (La
définition de
_GNU_SOURCE suffit également, et son usage
aurait été plus logique, puisque ces attributs sont tous
spécifiques à Linux.) Les attributs adéquats
sont :
MAP_32BIT,
MAP_ANONYMOUS (et son synonyme
MAP_ANON),
MAP_DENYWRITE,
MAP_EXECUTABLE,
MAP_FILE,
MAP_GROWSDOWN,
MAP_HUGETLB,
MAP_LOCKED,
MAP_NONBLOCK,
MAP_NORESERVE,
MAP_POPULATE, et
MAP_STACK.
BOGUES¶
Sous Linux, il n'y a aucune garantie comme celles indiquées plus haut
à propos de
MAP_NORESERVE. Par défaut, n'importe quel
processus peut être tué à tout moment lorsque le
système n'a plus de mémoire.
Dans les noyaux antérieurs à 2.6.7, le drapeau
MAP_POPULATE
n'avait d'effet que si
prot était
PROT_NONE.
SUSv3 indique que
mmap() devrait échouer si
length est 0.
Cependant, avec les versions de Linux antérieures à 2.6.12,
mmap() réussissait dans ce cas : aucune projection
n'était créée, et l'appel renvoyait
addr. Depuis
le noyau 2.6.12,
mmap() échoue avec le code d'erreur
EINVAL si
length est nul.
POSIX spécifie que le système devrait toujours remplir de
zéros toutes les pages incomplètes à la fin de l'objet et
que le système n'écrira jamais de modification de l'objet
au-delà de sa fin. Sous Linux, lors de l'écriture de
données vers ce genre de pages incomplètes après la fin
de l'objet, les données restent dans le cache de page même
après que le fichier soit fermé et déprojeté, et
même si les données ne sont jamais écrites vers le
fichier lui-même, les projections suivantes pourraient voir le contenu
modifié. Dans certains cas, cela pourrait être corrigé en
appelant
msync(2) avant la déprojection. Cependant, cela ne
fonctionne pas sur tmpfs (par exemple en utilisant l'interface de
mémoire partagée POSIX documentée dans
shm_overview(7)).
EXEMPLE¶
Le programme suivant affiche la partie du fichier, précisé par le
premier argument de la ligne de commande, sur la sortie standard. Les octets
qui seront affichés sont précisés à partir d'un
offset (déplacement) et d'une longueur en deuxième et
troisième paramètre. Le code fait une projection mémoire
des pages nécessaires du fichier puis utilise
write(2) pour
afficher les octets voulus.
Source du programme¶
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
char *addr;
int fd;
struct stat sb;
off_t offset, pa_offset;
size_t length;
ssize_t s;
if (argc < 3 || argc > 4) {
fprintf(stderr, "%s fichier offset [longueur]\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* Pour obtenir la taille du fichier */
handle_error("fstat");
offset = atoi(argv[2]);
pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
/* l'offset pour mmap() doit être aligné sur une page */
if (offset >= sb.st_size) {
fprintf(stderr, "L'offset dépasse la fin du fichier\n");
exit(EXIT_FAILURE);
}
if (argc == 4) {
length = atoi(argv[3]);
if (offset + length > sb.st_size)
length = sb.st_size - offset;
/* Impossible d'afficher les octets en dehors du fichier */
} else { /* Pas de paramètre longueur
==> affichage jusqu'à la fin du fichier */
length = sb.st_size - offset;
}
addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
MAP_PRIVATE, fd, pa_offset);
if (addr == MAP_FAILED)
handle_error("mmap");
s = write(STDOUT_FILENO, addr + offset - pa_offset, length);
if (s != length) {
if (s == -1)
handle_error("write");
fprintf(stderr, "écriture partielle");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
VOIR AUSSI¶
getpagesize(2),
mincore(2),
mlock(2),
mmap2(2),
mprotect(2),
mremap(2),
msync(2),
remap_file_pages(2),
setrlimit(2),
shmat(2),
shm_open(3),
shm_overview(7)
Dans
proc(5), les descriptions des fichiers
/proc/[pid]/maps,
/proc/[pid]/map_files, and
/proc/[pid]/smaps.
B.O. Gallmeister, POSIX.4, O'Reilly, pp. 128–129 et 389–391.
COLOPHON¶
Cette page fait partie de la publication 3.65 du projet
man-pages Linux.
Une description du projet et des instructions pour signaler des anomalies
peuvent être trouvées à l'adresse
http://www.kernel.org/doc/man-pages/.
TRADUCTION¶
Depuis 2010, cette traduction est maintenue à l'aide de l'outil po4a
<
http://po4a.alioth.debian.org/> par l'équipe de traduction
francophone au sein du projet perkamon
<
http://perkamon.alioth.debian.org/>.
Thierry Vignaud (2002), Alain Portal
<
http://manpagesfr.free.fr/> (2006). Julien Cristau et
l'équipe francophone de traduction de Debian (2006-2009).
Veuillez signaler toute erreur de traduction en écrivant à
<debian-l10n-french@lists.debian.org> ou par un rapport de bogue sur le
paquet
manpages-fr.
Vous pouvez toujours avoir accès à la version anglaise de ce
document en utilisant la commande «
man -L C
<section>
<page_de_man> ».