strace
is your friend here:
$ strace ./mmap-example mmap-example.c
...
... (lots of output)
...
open("mmap-example.c", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=582, ...}) = 0
mmap(NULL, 582, PROT_READ, MAP_FILE, 3, 0) = -1 EINVAL (Invalid argument)
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++
The mmap
man page tells you all you need to know ;)
EINVAL
We don't likeaddr
,length
, oroffset
(e.g., they are too large, or not aligned on a page boundary).EINVAL
(since Linux 2.6.12)length
was 0.EINVAL
flags
contained neitherMAP_PRIVATE
orMAP_SHARED
, or
contained both of these values.
The -EINVAL
error is caused by flags that cannot be 0. Either MAP_PRIVATE
or MAP_SHARED
has to be picked. I have been able to make it work by using MAP_PRIVATE
on Linux, x86-64.
So, you have just to add MAP_PRIVATE to mmap()
:
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/io.h>
#include <sys/mman.h>
int main(int argc, char const *argv[])
{
unsigned char *f;
int size;
struct stat s;
const char * file_name = argv[1];
int fd = open (argv[1], O_RDONLY);
/* Get the size of the file. */
int status = fstat (fd, & s);
size = s.st_size;
f = (char *) mmap (0, size, PROT_READ, MAP_PRIVATE, fd, 0);
for (int i = 0; i < size; i++) {
char c;
c = f[i];
putchar(c);
}
return 0;
}
NOTE: My first answer did include another possible cause for the EINVAL
:
size
must be an integral multiple of the page size of the system. To obtain the page size use the functiongetpagesize()
.
This is not actually required, but you must take into account that either way, mapping will be always performed in multiples of the system page size, so if you'd like to calculate how much memory is actually been available through the returned pointer, update size
as this:
int pagesize = getpagesize();
size = s.st_size;
size += pagesize-(size%pagesize);