简单的进程加载器内存映射

时间:2012-07-30 14:40:19

标签: c++ linux process virtual-memory memory-mapping

我正在为Linux编写一个非常简单的进程加载器。我正在加载的可执行文件已经编译好了,我知道每个可以在内存中找到的位置。我尝试的第一种方法是使用mmap()手动将每个代码或数据部分放在正确的位置,例如

mmap(addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0)

除非我删除MAP_FIXED标志,否则会出现段错误,因为看起来,一个块的地址与内存中已有的东西冲突,甚至可能与加载器本身冲突;地址0x401000似乎是有问题的。

我真的不确定从哪开始。一位朋友建议虚拟化内存访问操作;我不确定我会采取什么样的性能,而且我不知道它是如何完成的,但它可能是一种选择。我真正喜欢做的是创建一个“空”进程,就其本身而言,它将完全运行内存,因此在我想要之前不会将任何内容加载到用户空间中。 “空”过程的整个概念可能毫无意义,但它是描述我想要的最佳方式。我非常渴望能够帮助我的一些参考或例子。

1 个答案:

答案 0 :(得分:0)

在你的进程运行时(可能在“sleep(1000);”中打盹),查看它的/ proc / pid / maps。这将告诉你0x401000用于什么。

~$ sleep 1h &
[3] 2033
~$ cat /proc/2033/maps
00110000-002af000 r-xp 00000000 08:01 1313056    /lib/i386-linux-gnu/libc-2.15.so
...

在我的方框中,/ bin / sleep不使用该块,也不是我的小单行程序。

你可能在一些想要降落的图书馆中链接?

因此,一种方法是尽早分配你需要的块(早在main()运行之前 - 在其他地方查找该信息)。

另一种方法是将你的代码链接到你不知道的地址(可能是你自己生成x86操作码,或者“链接”,所以这不应该是一个延伸)。< / p>

另一个更好的选择是使代码可重定位。事实上,您不想更换或更少地替换整个进程的地址空间(正是exec所做的),这表明您的代码应该就是这样。

因此找到一个可用的地址,在那里加载这些位,并根据需要执行重定位(所以你的磁盘文件格式,如果它不是ELF,则需要包含reloc信息)。这是一条高路,你可以从装载机那里看到明显的东西。

当然,这几乎意味着自己重新实现dlopen()。我假设你只是想学习它是如何工作的 - 如果没有,那就是dlopen。 Stephane的规则零:它已经存在; - )

不要忘记支持链接代码中的其他库(无重复),dlclose(),初始值设定项,各种RTLD_ *模式,尊重MYCUSTOMLD_LIBRARY_PATH,GCC的__thread说明符等; - )