3

In Linux, is there a way (in user space) to map a virtual address range to the physical pages that back an existing virtual address range? The mmap() function only allows one to map files or "new" physical pages. I need to be able to do something like this:

int* addr1 = malloc(SIZE);
int* addr2 = 0x60000;      // Assume nothing is allocated here
fancy_map_function(addr1, addr2, SIZE);
assert(*addr1 == *addr2);  // Should succeed
assert(addr1 != addr2);    // Should succeed
I GIVE CRAP ANSWERS
  • 18,739
  • 3
  • 42
  • 47
boiler96
  • 1,167
  • 1
  • 8
  • 12
  • 1
    Is there a longer and deeper reason behind this? I can mmap(2) an MAP_ANONYMOUS | MAP_FIXED space at 0x600000 and then do `addr1 = addr2` to obtain almost what you want. Perhaps you have a chance with `shm_open(3)` - but I have a hunch you want something for which there is a more beautiful solution. – I GIVE CRAP ANSWERS Dec 10 '10 at 02:45
  • Yes, there's a longer and deeper reason behind this. Otherwise, you'd be right. :) – boiler96 Dec 10 '10 at 09:04

3 Answers3

3

I was curious so I tested the shared memory idea suggested in question comments, and it seems to work:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <assert.h>

#define SIZE 256
int main (int argc, char ** argv) {
  int fd;
  int *addr1, *addr2;

  fd = shm_open("/example_shm", O_RDWR | O_CREAT, 0777);
  ftruncate( fd, SIZE);
  addr1 = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  addr2 = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

  printf("addr1 = %p addr2 = %p\n", addr1, addr2);
  *addr1 = 0x12345678;
  assert(*addr1 == *addr2);  // Should succeed
  assert(addr1 != addr2);    // Should succeed

  return 0;
}

(Obviously real code will want to check the return value of the syscalls for errors and clean up after itself)

Chris Stratton
  • 39,853
  • 6
  • 84
  • 117
1

If you have the fd for the file mapped at addr1, you can simply mmap it again at addr2.

Otherwise, the Linux-specific remap_file_pages can modify the virtual address ⇆ file offset translation within a single VMA, with page-sized granularity, including mapping the same file offset to multiple addresses.

ephemient
  • 198,619
  • 38
  • 280
  • 391
  • The remap_file_pages function doesn't look quite right because the original memory is not from a file. It's anonymous mmap'ed memory. Still, I gave it a shot and it doesn't seem to work. After calling this, if I dereference addr2, I get a SIGSEGV. :( – boiler96 Dec 10 '10 at 17:55
  • @boiler96: Yeah, it'll only work on mapped files, not anonymous memory. You should have checked the return value before dereferencing `addr2` — it probably said `-1`, `errno=EINVAL`. – ephemient Dec 10 '10 at 18:48
  • Actually, it returned 0, which is very odd. I would have expected a -1 return code as well. Anyway, thanks for the thought. – boiler96 Dec 10 '10 at 21:30
-1

Open /proc/self/mem and mmap the range of virtual addresses you need from it.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • I get `ENODEV` when I try to `open("/proc/self/mem, O_RDWR)`. If I `open("/proc/self/mem", O_RDONLY)`, the subsequent `mmap(0, 4096, PROT_READ, MAP_SHARED, fd, addr1)` results in `ENODEV`. (Ubuntu 10.04 x86_64) – ephemient Dec 10 '10 at 04:48
  • I believe only a `ptrace()` parent is allowed to use `/proc//mem`. ISTR a discussion where it was determined that this is probably an unnecessary limitation, remaining only for historical reasons. – caf Dec 10 '10 at 06:11
  • Yes, I just tried this too, and it doesn't work. The mmap returns ENODEV. In a cruise through the latest kernel code I have (2.6.36), the mmap file operation is not mapped to a handler for the /proc/|self/mem stuff. Sadness. – boiler96 Dec 10 '10 at 17:16