虐阴缝b:Linux sys_exec中可执行文件映射的建立及读取 - 内核源码 - Linux论坛
来源:百度文库 编辑:九乡新闻网 时间:2024/07/14 02:03:21
1. 创建一个vm_area_struct;
2. 圈定一个虚用户空间,将其起始结束地址(elf段中已设置好)保存到vm_start和vm_end中;
3. 将磁盘file句柄保存在vm_file中;
4. 将对应段在磁盘file中的偏移值(elf段中已设置好)保存在vm_pgoff中;
5. 将操作该磁盘file的磁盘操作函数保存在vm_ops中;
6. 注意这里没有为对应的页目录表项创建页表,更不存在设置页表项了;
§ §
§ +------§->+--------------+
§ | § | Disk file |
§ | § | |
§ +----------------+ | +---§->|--------------|
§ | vm_area_struct | | | § | Seg Content |
§ |----------------| | | § |--------------|
+----------------+<-§-------- vm_start | | | § | |
| 圈定了一个未映 | § +----- vm_end | | | § | |
| 射到物理内存的 | § | | vm_file--------+ | § +--------------+
| vm_area_struct | § | | vm_pgoff ---------+ §
+----------------+<-§--+ | vm_ops --------+ §
§ | | | §
§ +----------------+ | §
§ | §
§ +----------------------+ §
§ | §
§ +->+-----------------------+ §
§ | file_private_map | §
§ |-----------------------| §
§ | nopage:filemap_nopage | §
§ | ..... | §
§ +-----------------------+ §
user space § kernel § disk
[ 本帖最后由 frank_seng 于 2008-5-6 15:45 编辑 ]
机器再胜人类 Power还能做什么? | 2010您最想感谢的CUer是谁? | 红帽RHCE超低价考试| 非诚勿扰 Unix专才招聘进行时! frank_seng
2楼 发表于 2008-05-06 15:44 | 只看该作者
* CPU依据CR3(current->pgd)找到0x08000011地址对应的pgd[ i ],由于该pgd[ i ]内容保持为初始化状态即为0,导致CPU异常;
* do_page_fault被调用,在该函数中,为pgd[ i]在内存中分配一个页表,并让该表项指向它,如下图所示:
pgd
+-----+
|-----| pt
| i |--->+-----+
|-----| |-----|
| | | j |
+-----+ |-----|
| |
+-----+
注意:这里i为0x08000011高10位,j为其中间10位,此时pt表项全部为0(pte[j]也为0);
* 为pte[j]分配一个真正的物理内存页面,依据vm_area_struct中的vm_file、vm_pgoff和vm_ops,调用filemap_nopage将磁盘file中vm_pgoff偏移处的内容读入到该物理页面中,如下图所示:
+-------------+
| Disk file |
| |
|-------------|
| Seg Content----+
|-------------| |
pgd | | |
+-----+ | | |②
|-----| pt +-------------+ |
| i |--->+-----+ |
|-----| |-----| ① page |
| | | j |------->+-----+<---+
+-----+ |-----| | |
| | | |
+-----+ | |
+-----+
①.分配物理内存页面;
②.从磁盘文件中将内容读取到物理内存页面中;
在do_fork->copy_mm中,如果vm_area_struct的属性中包含了可写属性,但非共享,则将父对应的pte[j](假设pte[j]对应了vm_area_strruct圈定的范围中的某个页面)设置为写保护,随后复制父pte[j]给子pte[j];此处采用了COW技术。
copy_mm之后的的情况如下图,可见并没有真正的复制一个page给子进程:
father
+--------+
| |
|--------|
|pte(w=0)|--+
|--------| |
| | |
+--------+ +-->+------+
| |
son +-->| |
+--------+ | | page |
| | | | |
|--------| | | |
|pte(w=0)|--+ | |
|--------| +------+
| |
+--------+
现在假设父进程向pte中写入,则会引发CPU异常,在异常处理机制中,处理如下:
* 创建一个新的newpage;
* 复制page内容到newpage;
* 让父pte指向newpage,并且设置父pte的w=1(可写);
* 子pte保持不变;最终如下图:
father
+--------+ +-->+------+
| | | | |
|--------| | | new |
|pte(w=1)|--+ | page |
|--------| | |
| | +------+
+--------+
son
+--------+ +-->+------+
| | | | |
|--------| | | page |
|pte(w=0)|--+ | |
|--------| | |
| | +------+
+--------+
如果现在子进程又向pte中写,同样导致异常,但是由于此时该pte:count==1,则直接将该pte:w=1,然后写即可;
son
+--------+ +-->+------+
| | | | |
|--------| | | page |
|pte(w=1)|--+ | |
|--------| | |
| | +------+
+--------+
[ 本帖最后由 frank_seng 于 2008-5-7 14:02 编辑 ] 真的好对不起,由于历史原因,我们的产品依然跑在Linux 2.4上,因此是对着2.4说的,2.6除了网络部分外,还从没看过,sorry啊!
关于COW,我写了一些总结性文档,贴出来献丑了:假设进程A创建了子进程B,之后进程A和进程B共享A的地址空间,同时该地址空间中的页面全部被标识为写保护。此时B若写address所在的页面,由于写保护的原因会引起写异常,在异常处理中,内核会将address所在的那个写保护页面复制为一个新的页面,让B的address页表项指向该新页面,新页面可写,而A的address页表项依然指向那个写保护的页面。此后当B再访问address是就会直接访问该新的页面了,不再会访问到那个写保护的页面。当A试图写address所在的页面时,由于写保护的原因此时也会引起异常,在异常处理中,内核如果发现该页面只有一个拥有进程,此种情况下也就是A,则直接对该页面取消写保护,此后当A再访问address是不会再有写保护错误了。如果此时A又创建了子进程C,则该address所在的页面又被设置为写保护,拥有进程为A和C,同时其他的页面例如PAGEX依然维持写保护,只是拥有进程为A、B和C。如果此时A访问PAGEX,则异常处理会创建一个新页面并将PAGEX中的内容复制到该页面,同时将A相应的pte指向该新页面。如果此时C也访问PAGEX,也会复制新页面并且让C对应的pte指向新页面。如果B再访问PAGEX,则由于此时PAGEX只有一个拥有进程B,故不再复制新页面,而是直接取消该页面的写保护,由于B的pte本来就直接指向该页面,所以无需再做其他工作了。这也就是COW的实现机制。
2. 圈定一个虚用户空间,将其起始结束地址(elf段中已设置好)保存到vm_start和vm_end中;
3. 将磁盘file句柄保存在vm_file中;
4. 将对应段在磁盘file中的偏移值(elf段中已设置好)保存在vm_pgoff中;
5. 将操作该磁盘file的磁盘操作函数保存在vm_ops中;
6. 注意这里没有为对应的页目录表项创建页表,更不存在设置页表项了;
§ §
§ +------§->+--------------+
§ | § | Disk file |
§ | § | |
§ +----------------+ | +---§->|--------------|
§ | vm_area_struct | | | § | Seg Content |
§ |----------------| | | § |--------------|
+----------------+<-§-------- vm_start | | | § | |
| 圈定了一个未映 | § +----- vm_end | | | § | |
| 射到物理内存的 | § | | vm_file--------+ | § +--------------+
| vm_area_struct | § | | vm_pgoff ---------+ §
+----------------+<-§--+ | vm_ops --------+ §
§ | | | §
§ +----------------+ | §
§ | §
§ +----------------------+ §
§ | §
§ +->+-----------------------+ §
§ | file_private_map | §
§ |-----------------------| §
§ | nopage:filemap_nopage | §
§ | ..... | §
§ +-----------------------+ §
user space § kernel § disk
[ 本帖最后由 frank_seng 于 2008-5-6 15:45 编辑 ]
机器再胜人类 Power还能做什么? | 2010您最想感谢的CUer是谁? | 红帽RHCE超低价考试| 非诚勿扰 Unix专才招聘进行时! frank_seng
- 发短消息
- 加为好友
frank_seng 当前离线
- UID
- 20588431
- 帖子
- 228
- 精华
- 2
- 积分
- 252
- 可用积分
- 252
- 信誉积分
- 100
- 专家积分
- 0
- 空间积分
- 0
- 阅读权限
- 20
- 在线时间
- 47 小时
- 注册时间
- 2007-07-17
- 最后登录
- 2010-06-30
![](http://image25.360doc.cn/DownloadImg/2011/03/1221/9931596_1.gif)
![](http://image25.360doc.cn/DownloadImg/2011/03/1221/9931596_2.gif)
![](http://image25.360doc.cn/DownloadImg/2011/03/1221/9931596_3.jpg)
精灵
- 帖子
- 228
- 主题
- 94
- 精华
- 2
- 可用积分
- 252
- 专家积分
- 0
- 在线时间
- 47 小时
- 注册时间
- 2007-07-17
- 最后登录
- 2010-06-30
状态:...当前离线...
[微博] [博客] [短信]
![](http://image25.360doc.cn/DownloadImg/2011/03/1221/9931596_5.gif)
回复 #1 frank_seng 的帖子
从上文中可知elf_map时并没有将文件内容读入内存,假设现在程序中有一条指令需要读取上面vm_start---vm_end之间的某内容,例如mov [0x08000011], %eax,那么将会执行如下序列:* CPU依据CR3(current->pgd)找到0x08000011地址对应的pgd[ i ],由于该pgd[ i ]内容保持为初始化状态即为0,导致CPU异常;
* do_page_fault被调用,在该函数中,为pgd[ i]在内存中分配一个页表,并让该表项指向它,如下图所示:
pgd
+-----+
|-----| pt
| i |--->+-----+
|-----| |-----|
| | | j |
+-----+ |-----|
| |
+-----+
注意:这里i为0x08000011高10位,j为其中间10位,此时pt表项全部为0(pte[j]也为0);
* 为pte[j]分配一个真正的物理内存页面,依据vm_area_struct中的vm_file、vm_pgoff和vm_ops,调用filemap_nopage将磁盘file中vm_pgoff偏移处的内容读入到该物理页面中,如下图所示:
+-------------+
| Disk file |
| |
|-------------|
| Seg Content----+
|-------------| |
pgd | | |
+-----+ | | |②
|-----| pt +-------------+ |
| i |--->+-----+ |
|-----| |-----| ① page |
| | | j |------->+-----+<---+
+-----+ |-----| | |
| | | |
+-----+ | |
+-----+
①.分配物理内存页面;
②.从磁盘文件中将内容读取到物理内存页面中;
父子页面保护共享的处理 ------ COW技术
在do_fork->copy_mm中,如果vm_area_struct的属性中包含了可写属性,但非共享,则将父对应的pte[j](假设pte[j]对应了vm_area_strruct圈定的范围中的某个页面)设置为写保护,随后复制父pte[j]给子pte[j];此处采用了COW技术。
copy_mm之后的的情况如下图,可见并没有真正的复制一个page给子进程:
father
+--------+
| |
|--------|
|pte(w=0)|--+
|--------| |
| | |
+--------+ +-->+------+
| |
son +-->| |
+--------+ | | page |
| | | | |
|--------| | | |
|pte(w=0)|--+ | |
|--------| +------+
| |
+--------+
现在假设父进程向pte中写入,则会引发CPU异常,在异常处理机制中,处理如下:
* 创建一个新的newpage;
* 复制page内容到newpage;
* 让父pte指向newpage,并且设置父pte的w=1(可写);
* 子pte保持不变;最终如下图:
father
+--------+ +-->+------+
| | | | |
|--------| | | new |
|pte(w=1)|--+ | page |
|--------| | |
| | +------+
+--------+
son
+--------+ +-->+------+
| | | | |
|--------| | | page |
|pte(w=0)|--+ | |
|--------| | |
| | +------+
+--------+
如果现在子进程又向pte中写,同样导致异常,但是由于此时该pte:count==1,则直接将该pte:w=1,然后写即可;
son
+--------+ +-->+------+
| | | | |
|--------| | | page |
|pte(w=1)|--+ | |
|--------| | |
| | +------+
+--------+
[ 本帖最后由 frank_seng 于 2008-5-7 14:02 编辑 ] 真的好对不起,由于历史原因,我们的产品依然跑在Linux 2.4上,因此是对着2.4说的,2.6除了网络部分外,还从没看过,sorry啊!
关于COW,我写了一些总结性文档,贴出来献丑了:假设进程A创建了子进程B,之后进程A和进程B共享A的地址空间,同时该地址空间中的页面全部被标识为写保护。此时B若写address所在的页面,由于写保护的原因会引起写异常,在异常处理中,内核会将address所在的那个写保护页面复制为一个新的页面,让B的address页表项指向该新页面,新页面可写,而A的address页表项依然指向那个写保护的页面。此后当B再访问address是就会直接访问该新的页面了,不再会访问到那个写保护的页面。当A试图写address所在的页面时,由于写保护的原因此时也会引起异常,在异常处理中,内核如果发现该页面只有一个拥有进程,此种情况下也就是A,则直接对该页面取消写保护,此后当A再访问address是不会再有写保护错误了。如果此时A又创建了子进程C,则该address所在的页面又被设置为写保护,拥有进程为A和C,同时其他的页面例如PAGEX依然维持写保护,只是拥有进程为A、B和C。如果此时A访问PAGEX,则异常处理会创建一个新页面并将PAGEX中的内容复制到该页面,同时将A相应的pte指向该新页面。如果此时C也访问PAGEX,也会复制新页面并且让C对应的pte指向新页面。如果B再访问PAGEX,则由于此时PAGEX只有一个拥有进程B,故不再复制新页面,而是直接取消该页面的写保护,由于B的pte本来就直接指向该页面,所以无需再做其他工作了。这也就是COW的实现机制。
Linux sys_exec中可执行文件映射的建立及读取 - 内核源码 - Linux论坛
Linux 2.6内核的编译步骤及模块的动态加载 - 内核源码学习 - Linux论坛
[转]Netfilter实现机制分析 - 内核源码 - Linux论坛
什么是module 以及如何写一个module(转) - 内核源码 - Linux论坛
写给Linux内核新手-关于Linux内核学习的误区
Linux内核里的DebugFS
深入分析Linux内核源码——(上)
LINUX中建立LVM卷
LINUX程序的虚拟内存映射机制
--Linux下的ping源码
linux内核sk_buff的结构分析
Linux内核打印函数printk的使用说明
使用 Linux 系统调用的内核命令
Linux 内核使用的 GNU C 扩展
Linux内核DMA机制
Linux内核驱动模块
linux内核map图
linux内核调试指南
[原创] 写给Linux内核新手-关于Linux内核学习的误区 - ChinaUnix.n...
UNIX/LINUX 平台可执行文件格式分析
Linux内核跟踪之syscall tracer | Linux系统(vps) - 小丽电脑论坛
Linux内核DMA机制 - ShangShuWu
Linux 内核中的 GCC 特性
linux内核调试指南ea