Linux сопоставляет диапазон виртуальной памяти с существующим диапазоном виртуальной памяти?

Есть ли в Linux способ (в пространстве пользователя) сопоставить диапазон виртуальных адресов с физическими страницами, которые поддерживают существующий диапазон виртуальных адресов? Функция mmap () позволяет отображать только файлы или «новые» физические страницы. Мне нужно сделать что-то вроде этого:

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

person boiler96    schedule 10.12.2010    source источник
comment
Есть ли за этим более долгая и глубокая причина? Я могу mmap (2) MAP_ANONYMOUS | MAP_FIXED пробел 0x600000, а затем выполните addr1 = addr2, чтобы получить почти то, что вы хотите. Возможно, у вас есть шанс с shm_open(3), но я подозреваю, что вам нужно что-то, для чего есть более красивое решение.   -  person I GIVE CRAP ANSWERS    schedule 10.12.2010
comment
Да, за этим есть более долгая и глубокая причина. В противном случае вы были бы правы. :)   -  person boiler96    schedule 10.12.2010


Ответы (3)


Мне было любопытно, поэтому я протестировал идею общей памяти, предложенную в комментариях к вопросу, и, похоже, она работает:

#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;
}

(Очевидно, что реальный код захочет проверить возвращаемое значение системных вызовов на наличие ошибок и очистить после себя)

person Chris Stratton    schedule 10.12.2010
comment
На самом деле это ближе всего к тому, что мне нужно. Я не думал об использовании shm_open. - person boiler96; 13.12.2010
comment
На самом деле это была идея «Я даю дерьмовые ответы» - я нашел ее достаточно интригующей, чтобы попробовать. - person Chris Stratton; 13.12.2010

Если у вас есть fd для файла, отображаемого в addr1, вы можете просто _ 2_ снова на addr2.

В противном случае специфичный для Linux remap_file_pages может изменять преобразование виртуального адреса ⇆ смещения файла в пределах одной VMA с гранулярностью размера страницы, включая отображение одного и того же смещения файла на несколько адресов.

person ephemient    schedule 10.12.2010
comment
Функция remap_file_pages выглядит не совсем правильно, потому что исходная память не из файла. Это анонимная ммап-память. Тем не менее, я попробовал, и, похоже, это не сработало. После этого вызова, если я разыменую addr2, я получаю SIGSEGV. :( - person boiler96; 10.12.2010
comment
@ котел96: Да, он будет работать только с отображенными файлами, а не с анонимной памятью. Вы должны были проверить возвращаемое значение перед разыменованием addr2 - вероятно, было сказано -1, errno=EINVAL. - person ephemient; 10.12.2010
comment
На самом деле он вернул 0, что очень странно. Я бы также ожидал получить код возврата -1. В любом случае спасибо за мысль. - person boiler96; 11.12.2010

Откройте /proc/self/mem и mmap нужный вам диапазон виртуальных адресов.

person R.. GitHub STOP HELPING ICE    schedule 10.12.2010
comment
Я получаю ENODEV, когда пытаюсь open("/proc/self/mem, O_RDWR). Если I open("/proc/self/mem", O_RDONLY), последующие mmap(0, 4096, PROT_READ, MAP_SHARED, fd, addr1) приводят к ENODEV. (Ubuntu 10.04 x86_64) - person ephemient; 10.12.2010
comment
Я считаю, что только ptrace() родитель может использовать /proc/<pid>/mem. ISTR - обсуждение, в ходе которого было определено, что это, вероятно, ненужное ограничение, оставшееся только по историческим причинам. - person caf; 10.12.2010
comment
Да, я тоже это пробовал, но не работает. Mmap возвращает ENODEV. В круизе по последнему коду ядра, который у меня есть (2.6.36), операция с файлом mmap не отображается на обработчик для материала / proc / ‹pid› | self / mem. Грусть. - person boiler96; 10.12.2010