I would like to allocate a buffer within 32-bit address space on 64-bit ARM. In other words, I would like to ensure that my buffer is bound to the lower 32-bit address space. Do you know a nice C function which does that?
There is no C standard function to do so. However, since you tagged the question as Linux, take a look at mmap(2) and the MAP_ANONYMOUS and MAP_32BIT flags, e.g.:
mmap(
0, 1,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT,
-1, 0
);
Another option is passing an explicit address in the lower 32-bit address space using the MAP_FIXED flag:
mmap(
(void *)0x10000, 1,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
-1, 0
);
Related
How to read mmap function from specific address, if knew it (0x6A6F7444)?
I tried:
mmap(0x6A6F7444, 100, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)
But it doen't works. Compile says:
warning: passing argument 1 of ‘munmap’ makes pointer from integer without a cast [-Wint-conversion]
#include <stdint.h> // for uintptr_t
uintptr_t addr = 0x6A6F7444;
mmap((void *)addr, 100, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
will disable the warning.
For mmap to use your address it needs MAP_FIXED flag, see man mmap for full details.
Despite continued interest there is still no way to create a “cow-copy” of a memory region on Linux. With the inception of the memfd_create(2) syscall, the situation has slightely improved, as one does not have to create an explicit file any more for shared memory.
I am wondering, why isn't there a thing like the following?
void *ptr = mmap((void *)0, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, (size_t)0);
void *ptr2= mremap(ptr, 0, size, MREMAP_MAYMOVE | MREMAP_COW);
The intended semantics are that ptr2 and ptr share the underlying memory, but a write from either will trigger a copy-on-write with page-granularity.
Is this just a case of “nobody bothered to implement this yet” or am I missing something technical?
I've been pulling my hairs out for hours on this very basic piece of code and I haven't managed to understand why mmap(2) was failing.
#include <sys/mman.h>
#include <sys/user.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#define NPAGES 50
#define SLABSIZE (PAGE_SIZE * NPAGES) // 200 kB
int
main(int argc, char *argv[])
{
char *slab;
printf("DEBUG: mmap(%#x, %u, %#x, %#x, %d, %u)\n",
NULL, SLABSIZE, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
slab = mmap(NULL, SLABSIZE, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
if (slab == MAP_FAILED)
err(1, "mmap");
}
But when I run it:
$ make mmap
cc mmap.c -o mmap
$ ./mmap
DEBUG: mmap(0, 204800, 0x3, 0x20, -1, 0)
mmap: mmap: Invalid argument
I checked and re-checked mmap(2)'s manpage [1], and it seems that all requirements are OK but I must be missing something.
I'm running Linux kernel 4.8.13.
Thanks.
-- Jeremie
[1] http://man7.org/linux/man-pages/man2/mmap.2.html
When strace ing your program, I see:
mmap(NULL, 204800, PROT_READ|PROT_WRITE, MAP_FILE|MAP_ANONYMOUS, -1, 0) = -1 EINVAL (Invalid argument)
You forgot a MAP_SHARED flag (or a MAP_PRIVATE one). With it (either MAP_SHARED or MAP_PRIVATE, but you need one of them) your program works:
slab = mmap(NULL, SLABSIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
Quoting the mmap(2) man page:
This behavior is determined by including exactly one of the following values in flags:
(emphasis is mine)
MAP_SHARED
Share this mapping. Updates to the mapping are visible to
other processes mapping the same region, and (in the case of
file-backed mappings) are carried through to the underlying
file. (To precisely control when updates are carried through
to the underlying file requires the use of msync(2).)
MAP_PRIVATE
Create a private copy-on-write mapping. Updates to the
mapping are not visible to other processes mapping the same
file, and are not carried through to the underlying file. It
is unspecified whether changes made to the file after the
mmap() call are visible in the mapped region.
So the general advice before pulling your hairs: read once again the documentation; take a nap; read another time the documentation and think about what did you miss.
Another hint would be to use strace(1) on some (or several) existing executable(s). You'll learn a lot.
I get segmentation fault when I run the following piece of code...
int * x = mmap( 0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE, 0, 0 );
x[0] = 42; // <--- Segmentation fault happens due to this
What is wrong here?
You've specified the incorrect flags and file descriptor. It looks like what you want is an anonymous (not backed by a file) mapping. If that's the case, the correct call would be:
x = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
You need to use the MAP_ANONYMOUS flag to tell Linux there is no file. And you should pass -1 for the file descriptor, not 0.
OK, I got it. I forgot to place MAP_ANONYMOUS, so it should had been like this...
int * x = mmap( 0, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE,
0, 0 );
Its working this way.
man mmap says:
On success, mmap() returns a pointer to the mapped area. On error, the value MAP_FAILED (that is, (void *) -1) is returned, and errno is set appropriately
Check, whether x == MAP_FAILED or not. May be this is the case.
And you should always check that the result of mmap is not MAP_FAILED (that is, (void *) -1) and use errno to get the error code in that case.
Your mmap could fail (e.g. because of resource limits set with setrlimit, or because the swap space is full).
I created my shared memory and mapped my object with following code:
shmfd = shm_open(SHMOBJ_PATH, O_CREAT | O_EXCL | O_RDWR, S_IRWXU | S_IRWXG);
ftruncate(shmfd, shared_seg_size);
bbuffer = (boundedBuffer *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
Now I need to initialize and add/remove items to/from bbuffer. When I try to add/remove, I get Segmentation Fault: 11, which indicates the program accessed a memory location that was not assigned. What can I do to solve this problem?
A wild guess:
perhaps you don't have the header file for mmap included
and you are on an architecture with 64 bit void* and 32 bit int
What could happen there is that the compiler takes mmap as returning int by default, casts this into a pointer and by that clashes the higher order bits.
Never cast return values from functions such as malloc or mmap, and always take the warnings of your compiler seriously.