进程虚拟内存

Posted

技术标签:

【中文标题】进程虚拟内存【英文标题】:Process virtual memory 【发布时间】:2013-12-13 12:45:50 【问题描述】:

进程在他的同一个地址空间中可以有几个虚拟页指向同一个物理地址吗?

我想要那个 virt_page1---> 物理-X 还有那个 virt_page2 ---> physical-X

怎么做?应该从内核空间完成吗? 涉及哪些套路?

如果我想像这样映射共享库:

7ff2a90d8000-7ff2a928d000 r-xp 00000000 08:02 4980747 /lib/x86_64-linux-gnu/libc-2.15.so 7ff2a928d000-7ff2a948d000 ---p 001b5000 08:02 4980747 /lib/x86_64-linux-gnu/libc-2.15.so 7ff2a948d000-7ff2a9491000 r--p 001b5000 08:02 4980747 /lib/x86_64-linux-gnu/libc-2.15.so 7ff2a9491000-7ff2a9493000 rw-p 001b9000 08:02 4980747 /lib/x86_64-linux-gnu/libc-2.15.so

我看到映射是私有的,这是否意味着我不能再次将它们映射到其他虚拟地址?我应该为此更改链接器吗?

更新:

在禁用 ASLR 时,我执行了以下操作:

int main(void)

  int fd = open("/lib/x86_64-linux-gnu/libc-2.15.so", O_RDONLY);
  void* f1 = mmap(0, 1748*1024, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
  void *f2 = (void*)0x00007ffff7a1a000;

  if (memcmp(f1, f2, 1748*1024) != 0) 
      printf("DIFFER\n");
  
  while(1);
  return 0;

这是没有ASLR时的.so映射 00007ffff7a1a000 1748K r-x-- /lib/x86_64-linux-gnu/libc-2.15.so

所以我将上面的区域映射到其他页面,我得到了这个:

00007ffff7e26000 1748K r-x-- /lib/x86_64-linux-gnu/libc-2.15.so

当我比较 f1 和 f2 时,我看到相同的数据, 是说我现在必须将虚拟区域映射到相同的物理地址,即 1748K 的共享库部分?

【问题讨论】:

这听起来类似于共享内存或内存映射。看看这些,看看他们是否按照您的意愿行事。 你能给我举个例子吗?它是同一进程内的共享内存吗?我不想与其他进程共享页面...我希望 x1 进程有几个页面指向相同的物理内存 你真正想要达到的目标变得越来越不清楚。 我想通过另一个虚拟地址映射来实现共享库的相同映射(只有只读部分),我上面写的例子实现了吗? 是的,它应该可以工作,但你为什么要这样做? 【参考方案1】:

是的,它可以从用户空间。最简单的方法是mmap同一个文件两次。

char templ[] = "XXXXXXXX";
int fd = mkstemp(templ);
ftruncate(fd, 1024);
void* f1 = mmap(0, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
void* f2 = mmap(0, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
strcpy (f1, "foo bar baz weep quup");
printf ("%p %s\n", f1, (char*)f1);
printf ("%p %s\n", f2, (char*)f2);

【讨论】:

但是,如果文件是共享库,在加载进程时由链接器映射,会发生什么?如果我再次对每个区域(我可以从 /proc/PID/maps 读取)的库(具有确切的权限和大小)进行 mmap,那么新映射将作为共享库的精确映射吗?如何测试它以查看映射是否相同?区域之间的 memcmp 就足够了吗? 在共享库中,映射是私有的,所以我不能这样做? 在禁用 ASLR 时我做了 int main(void) int fd = open("/lib/x86_64-linux-gnu/libc-2.15.so", O_RDONLY);无效* f1 = mmap(0, 1748*1024, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);无效 f2 = (void)0x00007ffff7a1a000; if (memcmp(f1, f2, 1748*1024) != 0) printf("DIFFER\n"); 而(1);返回0; 对于只读区域,这无关紧要。如果您将一个读写区域私下映射两次,则通过一个映射写入的内存不会反映到另一个映射中,这可能是您想要的,也可能不是。

以上是关于进程虚拟内存的主要内容,如果未能解决你的问题,请参考以下文章

鸿蒙轻内核虚拟内存基础知识:虚拟内存进程空间编号

虚拟内存

如何查看java虚拟机堆内存的参数值

虚拟内存与进程地址空间

期末复习——虚拟内存

linux进程内存相关