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

标签 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 标志,否则会出现段错误,因为看起来一个 block 的地址与内存中已有的内容冲突,甚至可能是加载程序本身;地址 0x401000 似乎是有问题的地址。

我什至不确定从哪里开始。一位 friend 建议虚拟化内存访问操作;我不确定我会为此采取什么样的性能打击,而且我不知道它是如何完成的,但这可能是一个选择。我真正喜欢做的是创建一个“空”进程,就它而言,它可以完全运行内存,因此在我想要它之前,不会将任何东西加载到用户空间。 “空”过程的整个概念可能毫无意义,但这是描述我想要的东西的最佳方式。我非常渴望获得一些可能对我有帮助的引用资料或示例。

最佳答案

随着您的进程运行(可能在“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 没有使用那个 block ,我的小单行程序也没有。

您可能正在链接一些想要登陆的库?

因此,一种方法是尽早分配您需要的 block (早在 main() 运行之前——在别处寻找该信息)。

另一种方法是将您的代码链接到某个您“知道”未被占用的地址(大概是您自己生成 x86 操作码,或者以其他方式“链接”,所以这不应该是一个延伸)。

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

因此,找到一个可用地址,将位加载到那里,并根据需要执行重定位(因此,如果您的磁盘文件格式不是 ELF,则需要包含重定位信息)。这是一条高速公路,也是您下一步想要从加载程序中获得的显而易见的东西。

当然,这几乎意味着您自己重新实现 dlopen()。我假设您只是想了解它是如何工作的——如果不是,man dlopen。 Stephane 的零规则:它已经存在 ;-)

不要忘记支持从您的代码链接其他库(无重复)、dlclose()、初始化器、各种 RTLD_* 模式、荣誉 MYCUSTOMLD_LIBRARY_PATH、GCC 的 __thread 说明符等。;-)

关于c++ - 简单的进程加载器内存映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11723758/

相关文章:

c++ - 从嵌套类的函数访问父类的非静态成员

c++ - Windows 10 是否会防止您访问其他程序正在使用的内存?

c++ - QCustomPlot 填充连接线

linux - 如何确定我的 shell 管道中最慢的组件?

c++ - Poco进程不退出

C++ 我需要重载哪些运算符才能使这个 A1 += A2 * floatValue 工作?

java - 限制可用处理器

Linux:什么是链接

process - 这个支付用户的过程是否可靠和安全?

linux - 从后台获取用户输入