在了解creat_tables()这个函数之前,我想先要明白他上面的几个p值是什么,在do_execve()中定义:
unsigned long p = PAGE_SIZE*MAX_ARG_PAGES-4; //P指向参数和环境变量的最后部
其次336,,337行上的p值是128kb参数和环境变量空间中的偏移值:
p = copy_srtings(envc,envp,page,p,0);
再向下看就是364,和365
p+ = change_ldt(ex,a_text,page); //返回段限长
p- = LIBRARY_SIZE + MAX_ARG_PAGES*PAGE_SIZE;
这两行中,第一行返回数据段的长度:64M,得到这个长度然后再与上面的p值(偏移量)相加,再减去库文件和128KB的参数和环境变量值(例如:p的偏移值为128kb-34,则:p = 128kb-34b + 64M - 4M - 128kb = 60M-34b),于是p被调整为从进程逻辑地址空间开始算起的参数和环境变量起始指针。(为什么要用逻辑地址,我们往下看)
进入creat_tables()函数:
sp = (unsigned long *)(0xfffffffc & (unsigned long) p);
sp -= envc +1;
envp = sp;
sp -= argc+1;
argv = sp;
put_fs_long((unsigned long)envp,--sp);
put_fs_long((unsigned long)argv,--sp);
put_fs_long((unsinned long)argc,--sp);
下面这个图很好的反应了上面的代码:
下面我们来分析一下put_fs_long()这个函数(segment.h):
put_fs_long(unsigned long val,unsigned long *addr)
{
_asm_ ("movw %0,%%fs:%1"::"r"(val),"m"(*addr));
}
我认为这个函数就是我们上面使用逻辑地址的原因,这个函数已经设置好了段选择子,fs指向局部数据段描述符,取段描述符中的线性基地址,再拿这个线性基地址加上偏移量,最后形成一个线性地址:
拿进程2来说,线性基地址被设置成128M,所以线性地址就是128M+60M-34了,val也会被设置到这个线性地址处。
就是指针的对应关系了,不说了,睡了