Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1755891
  • 博文数量: 76
  • 博客积分: 2175
  • 博客等级: 大尉
  • 技术积分: 2481
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-20 20:49
个人简介

欢迎光临我的博客

文章分类

全部博文(76)

文章存档

2018年(4)

2017年(1)

2016年(2)

2015年(2)

2013年(5)

2012年(29)

2010年(33)

分类: 系统运维

2012-11-01 21:20:34




From: quntmec@hotmail.com
To: qf.hao@hotmail.com
Subject: RE: 关于《UNIX技术内幕》的勘误及遇到的问题_21
Date: Tue, 14 Feb 2012 10:14:31 +0800

郝先生,

上一封邮件的问题:
--------------------------------
问题3:一个进程应该只对应存在一个u变量(即,一个进程不可能既存在一个u变量在“用户空间“、又存在一个u变量在“内核空间“),是吗?如果是,那参 照81页,图5-6,一个进程的u变量应该与其内核栈一起(大小为1KB),且对其访问也只能在进程处于内核态时进行。那为何readi函数可以将 exefile 的头8个字节 读到 “用户空间“(或用户态下)的u变量中?
[郝]:不是很理解你的问题,为什么说readi是把头8个字节读到用户空间的u变量中?书中哪里提到吗?exec函数的所有代码包括readi函数都是在内核空间中,u变量也是。

---------------------------------

在502页,第64行,u.u_segflg=1,表明后面的 readi操作(第65行)是将数据(头8个字节)读入至“用户空间”。是否是我理解错?
[郝]:不好意思,在第316页对readi的说明有误,应该是:如果u.u_segflg为1,则u.u_base在内核空间...,因为这来自于第318页的iomove函数。所以实际上readi把头8个字节读入到内核的u.u_arg[]变量中



From: qf.hao@hotmail.com
To: quntmec@hotmail.com
Subject: RE: 关于《UNIX技术内幕》的勘误及遇到的问题_21
Date: Sun, 12 Feb 2012 22:24:19 +0800




From: quntmec@hotmail.com
To: qf.hao@hotmail.com
Subject: 关于《UNIX技术内幕》的勘误及遇到的问题_21
Date: Sun, 15 Jan 2012 19:49:24 +0800

郝先生,

最近碰到的疑问如下:

1、不太明白 466页第一段里对464页trap()函数第71行的解释。如果将464页trap()函数第71行改为(不调用trap1函数):

savu(u.u_qsav);
callp->call;

是否这也能实现trap1的功能?
[郝]:答案是不能!因为savu保存的是当前函数的返回地址,如果trap调用savu,就是trap的返回地址,这样在调用callp->call的过程中,如果callp->call调用了sleep,而sleep过程中有产生了
信号,那么sleep函数就会直接返回到trap的调用者中,而这并不是所想要的,其所想要的是能够返回到trap函数的第72行,继续执行。所以这里必须要调用一次trap1,而由trap1调用savu。这就是trap1存在的价值。

2、 465页,图12-5,其中左边“用户空间“的指令序列为“trap0,addr,下一条指令“。473页,图12-10,上面“用户空间“的指令序列为 “sys0,9f,bec 1f”。问题,本章开始时曾提到在本章中trap跟sys指令含义相同,则可以认为 图12-10中的 9f 是一个addr(如图12-5中的addr),是这样吗?

另,9f是一条指令吗?如果是,那它与 br 9f 有什么不同?
[郝]:9f是addr,它就是br 9f中的地址。

3、以下是关于 exec()

因为这个函数的内容比较多,我简化一些称呼,如:“exec进程”代表“旧进程“,"exefile进程“代表“新进程“。对于exec,我的理解如下:

(1)分配一个新的块,用以保存 execl 的参数,代码范围:19~51。

问题2:501页,exec函数第29~47行,为何ap(即arg1,ap=arg1=*(&u.u_arg[1]))一定是一个指针?且一定是一个字符指针(指向一个字符串)?
[郝]:execl的原型应该是int execl(char *exe, char *arg1, char *arg2,..., 0);
(2) 读入可执行文件exefile的文件头的8个字节,代码范围:60~84。读入过程,由readi将exefile从磁盘读入至“用户空间 “(u_segflg=1)的u变量中,具体是u_arg[1]=a_text;u_arg[2]=a_data;u_arg[3]=a_bss。

问 题3:一个进程应该只对应存在一个u变量(即,一个进程不可能既存在一个u变量在“用户空间“、又存在一个u变量在“内核空间“),是吗?如果是,那参照 81页,图5-6,一个进程的u变量应该与其内核栈一起(大小为1KB),且对其访问也只能在进程处于内核态时进行。那为何readi函数可以将 exefile 的头8个字节 读到 “用户空间“(或用户态下)的u变量中?
[郝]:不是很理解你的问题,为什么说readi是把头8个字节读到用户空间的u变量中?书中哪里提到吗?exec函数的所有代码包括readi函数都是在内核空间中,u变量也是。
(3)初步建立用户空间映射,以测试(系统的空闲内存 + exec进程所占内存)是否够“exefile进程“所使用。代码范围:90~93。

(4)设置“exefile进程“的代码段和“u+内核栈“。代码范围:99~106。具体为:

a)调用xfree()释放 “exec进程”的代码段
b)调用expand(USIZE)释放“exec进程“的数据段和栈段,只保留“exec进程”的“u+内核栈”
c) 调用xalloc()为“exefile进程“的代码段分配磁盘交换空间和为“exefile进程”保留“exec进程“的“u+内核栈”(假设 exefile第一次加载,exefile的代码段和“u+内核栈”都交换至磁盘,具体参看xalloc()中的第35行和第46行这2句swap)。
d)调用expand扩展“exec进程“的数据交换区,并将“exec进程”的数据段和栈段清0。

(5)将可执行文件 exefile 的数据段(a_data)读入内存。代码范围:108~112。具体为:将"exefile进程“的数据段内容读入至“exec进程”的数据段中。

问题4:u_base=0,是否代表从数据段的(虚拟地址)0地址开始操作?
[郝]:这里是建立一个临时的起始虚拟地址为0的虚拟<--->物理地址空间,其目的就是为了读入exe文件中的数据段内容到该地址空间。而数据段最终的起始虚拟地址不是0.
问 题5:如果是的话,那参看510页xalloc函数第29~32行,“exefile进程”的代码段是曾经被读入到“exec进程”的数据段里的,范围是 [020,(020+a_text)]。而回到本函数(exec函数)里的第109~112行,“exefile进程”的数据段也是被读到“exec进 程”的数据段里,范围是[(020+a_text),(020+a_text+a_data)]。很显然,作者是想把“exefile进程”的代码段、数 据段在“exec进程”的数据段里连续存放(或简单说是在内存中连续存放)。但是,在这2段代码之间,具体是xalloc函数的第41行,已调用 expand(USIZE)释放了“exefile进程”的代码段。也就是,系统先在ialloc的第29~32行将“exefile进程”的代码段读入 到“exec进程”的数据段[020,(020+a_text)],但在第41行就释放了该代码段。然后回到exec函数里,将“exefile进程”的 数据段读入到“exec进程”的数据段里[(020+a_text),(020+a_text+a_data)]。原本看上去在内存中连续存放的 (exefile进程)“数据段和代码段“,经过中间“第41行释放(exefile进程)代码段“后,是否还保持空间上的连续?如果不能保持空间上的连 续,那为何在exec函数里(第108~112)还将“exefile进程”的数据段读入到“exec进程”的数据段[(020+a_text), (020+a_text+a_data)]里?
[郝]:首先作者并没有想把“exefile进程”的代码段、数据段在“exec进程”在内存中连续存放,其次记住一点:exec/xalloc函数中使用estabur建立的0地址开始的虚拟地址段,在上述情况下
只是临时使用,xalloc是用来拷贝代码然后调用swap换出到磁盘,下次exeFile进程执行时,需要把该段再换入到内存中。
希望能够给予这一点再思考上述代码。

(6)初始化栈段。代码范围:116~132。具体:

a)设置最终的用户虚拟空间(516页,如图:12-30),这是由第120行代码(estabur())完成的。

问 题6:假设(5)的问题不存在,即“exefile进程”的代码段和数据段都读到“exec进程”的数据段里,且是连续的,范围是[020, (020+a_text+a_data)]。即对于 81页 图5-6,中间的图“物理内存”部分是有的。而由于estabur函数(代码第120行)的调用,图5-6中的虚拟内存部分也是有的。但是如何实现“物理 内存“到“虚拟内存“之间的映射呢?
[郝]:在sureg函数中。estabur建立设置进程用户空间逻辑寄存器的值(u.u_uisa和u.u_uisd),设上它们并不会导致物理内存和虚拟内存的映射。而虚拟和物理内存的映射是在
sureg函数中,它在estabur的最后被调用,sureg把u_uisa和u_uisd写到实际的内存管理寄存器中(系统只有一份),这样导致
虚拟和物理内存的映射。
b)构建main的栈参数

问题7:exec函数的第122行代码:ap = -nc - na*2 -4。如果nc为argv[X],na*2为各个栈上参数(栈上的指针,每个2字节),那4是否就代表 na本身(即argc)和 -1 这2个数?
[郝]:内存是所有参数字符的总长度,strlen(argv[0])+...+strlen(argv[n]),4代表exefile和0.
问题8:ap 和 c 都不是绝对地址(这个词可能不太准确,但ap和c至少不是物理地址和虚拟地址),而只是1个“相对位移”(我不太确定它是否是相对栈顶的位移)。那为何可以通过 suword() 实现数据写入?
[郝]:ap是exefile进程的栈顶地址,是虚拟地址。
(7)其他步骤(从略)



问题1:上面的理解对吗?
[郝]:对!除了问题部分。
问题2:(1)

问题3:(2)

问题4、问题5:(5)

问题6、问题7:(6)
 

此外,勘误如下:

468 1 1 ...输入而控起...,应为挂起
493

最后一行,hoo()应为 foo()

[郝]:是的,谢谢!

Steve








《返璞归真--UNIX技术内幕》在全国各大书店及网城均有销售:

                         
                       



阅读(5616) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~