The MMAP System Call in Linux (
Page 1 of 4 )
In this third part of a seven-part series on Linux I/O file system calls, you'll learn how to use the mmap() system call, which will give you some flexibility when handling files. This article is excerpted from chapter four of the book Linux System Programming: Talking Directly to the Kernel and C Library, written by Robert Love (O'Reilly, 2007; ISBN: 0596009585). Copyright © 2007 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.
Mapping Files into Memory
As an alternative to standard file I/O, the kernel provides an interface that allows an application to map a file into memory, meaning that there is a one-to-one correspondence between a memory address and a word in the file. The programmer can then access the file directly through memory, identically to any other chunk of memory-resident data—it is even possible to allow writes to the memory region to transparently map back to the file on disk.
POSIX.1 standardizes—and Linux implements—the
mmap()
system call for mapping objects into memory. This section will discuss
mmap()
as it pertains to mapping files into memory to perform I/O; in Chapter 8, we will visit other applications of
mmap()
.
mmap( )
A call to mmap() asks the kernel to map len
bytes of the object represented by the file descriptor
fd
, starting at
offset
bytes into the file, into memory. If
addr
is included, it indicates a preference to use that starting address in memory. The access permissions are dictated by
prot
, and additional behavior can be given by
flags
:
#include <sys/mman.h>
void * mmap (void *addr,
size_t len,
int prot,
int flags,
int fd,
off_t offset);
The addr parameter offers a suggestion to the kernel of where best to map the file. It is only a hint; most users pass 0. The call returns the actual address in memory where the mapping begins.
The
prot
parameter describes the desired memory protection of the mapping. It may be either
PROT_NONE
, in which case the pages in this mapping may not be accessed (making little sense!), or a bitwise OR of one or more of the following flags:
PROT_READ
The pages may be read.
PROT_WRITE
The pages may be written.
PROT_EXEC
The pages may be executed.
The desired memory protection must not conflict with the open mode of the file. For example, if the program opens the file read-only,
prot
must not specify
PROT_WRITE
.
Protection Flags, Architectures, and Security
While POSIX defines four protection bits (read, write, execute, and stay the heck away), some architectures support only a subset of these. It is common, for example, for a processor to not differentiate between the actions of reading and executing. In that case, the processor may have only a single “read” flag. On those systems, PROT_READ implies PROT_EXEC. Until recently, the x86 architecture was one such system.
Of course, relying on such behavior is not portable. Portable programs should always set
PROT_EXEC
if they intend to execute code in the mapping.
The reverse situation is one reason for the prevalence of buffer overflow attacks: even if a given mapping does not specify execution permission, the processor may allow exe
cution anyway.
Recent x86 processors have introduced the NX (no-execute) bit, which allows for readable, but not executable, mappings. On these newer systems,
PROT_READ
no longer implies
PROT_EXEC
.
The
flags
argument describes the type of mapping, and some elements of its behavior. It is a bitwise OR of the following values:
MAP_FIXED
Instructs
mmap()
to treat
addr
as a requirement, not a hint. If the kernel is unable to place the mapping at the given address, the call fails. If the address and length parameters overlap an existing mapping, the overlapped pages are discarded and replaced by the new mapping. As this option requires intimate knowledge of the process address space, it is nonportable, and its use is discouraged.
MAP_PRIVATE
States that the mapping is not shared. The file is mapped copy-on-write, and any changes made in memory by this process are not reflected in the actual file, or in the mappings of other processes.
MAP_SHARED
Shares the mapping with all other processes that map this same file. Writing into the mapping is equivalent to writing to the file. Reads from the mapping will reflect the writes of other processes.
Either
MAP_SHARED
or
MAP_PRIVATE
must be specified, but not both. Other, more advanced flags are discussed in Chapter 8.
When you map a file descriptor, the file’s reference count is incremented. Therefore, you can close the file descriptor after mapping the file, and your process will still have access to it. The corresponding decrement of the file’s reference count will occur when you unmap the file, or when the process terminates.
As an example, the following snippet maps the file backed by
fd
, beginning with its first byte, and extending for
len
bytes, into a read-only mapping:
void *p;
p = mmap (0, len, PROT_READ, MAP_SHARED, fd, 0)
;
if (p == MAP_FAILED)
perror ("mmap");
Figure 4-1 shows the effects of paramaters supplied with
mmap()
on the mapping between a file and a process’ address space.

Figure 4-1. Mapping a file into a process' address space