您的位置:首页 > 运维架构 > Linux

linux0.11 内核启动代码分析(二)

2015-12-02 20:46 495 查看
1、 fs寄存器 和 ds寄存器

赵炯老师的解释是:

在进程进入内核态后, fs寄存器默认指向进程的数据段。 而ds,es寄存器则指向内核数据段。

在用户态运行时,这些寄存器都指向用户数据段。

FS寄存器指向当前活动线程的TEB结构

偏移 说明

000 指向SEH链指针

004 线程堆栈顶部

008 线程堆栈底部

00c subsystemTib

010 FiberData

014 ArbitraryUserPointer

018 FS段寄存器在内存中的镜像位置

020 进程PID

024 线程ID

02c 指向线程局部存储指针

030 PEB结构地址

034 上个错误号

举个例子 pop DWORD PTR FS:[004] ; 在这里就是引用FS段寄存器得到段描述符 然后加上偏移地址004来访问内存地址

改地址是线程堆栈顶部,那么该语句的作用就是 将堆栈顶部的4个字节的 的内容弹出去。

在 intel汇编中,没有寄存器名的存在的情况下,用操作符号 ptr指明内存单元的长度 。 DWORD代表4字节(32位)

2、 同上一个问题, gs段寄存器的作用 不清楚 ???以后再来查阅相关资料

3、 研究一下代码段:

call setup_gdt;

...

setup_gdt:

lgdt lgdt_opcode

ret

...

lgdt_opcode:

.word (end_gdt-gdt) - 1

.long gdt

...

gdt:

#具体的段描述符

....

end_gdt:

.fill 128,4,0

第一点:

根据boot.s上代码及其网上资料分析, lgdt指令的操作数应该是一个32位的内存地址。

(这个地址是物理地址),但是在此处, 32位的地址直接引用的是 gdt的地址。 我们知道在 段机制下, 基地址加上偏移地址才能得到

物理地址(在我们讨论的范围内,不考虑分页机制)。那么问题来了! 为什么这里直接使用了偏移地址??

答案是 : 在boot.s 的代码中, 进入保护模式时,设置了一个 GDT表,此时的cs寄存器值为0x8, 我们已经进入了保护模式,

接下来的代码是重新设置 GDT和LDT,cs代码段寄存器 不变化。 但是 还有一个问题,就是ds寄存器 为什么在head.s中需要初始化,

原因时,DS的值我们不知道! 所以需要初始化,为什么是0x10,因为在boot.s中设置的数据段的 index是0x10. 经过了这些处理,

答案已经很明确了,那就是 基地址是 0x0 ! 故加不加基地址没有任何影响。

第二点:

这个 .fill 128,4,0; 指令是何作用

答案: 根据这段代码很自然的,又联系上了 init_stack: .long init_stack .word 0x10; 和LSS init_stack,%esp 这几个指令。

让我来一个个分析。 首先我一直对这个 end_gdt 这个标号理解不是很深刻, 其实它就是一个 地址。当做指针来了解吧。

首先 要知道的是 栈 是 向下增长的, 向下增长的意思是, 栈的 基地址 是高位物理地址, 存储的元素的物理地址越来越低。

这个 .fill 指令 就是在 上述 GDT 地址的后面 将后面 128 *4字节大小的空间初始化为0 。 然后下面 就是init_stack标号。

一句话就是 init_stack 表示的地址 和 GDT 描述符表 之间的空间是 128*4字节。 而这就是内核栈的空间大小。接下来是

LSS指令 的 源操作数只能是 存储器寻址方式,也就是内存寻址方式。init_stack代表了栈的初始地址, .long init_stack则是

表示一个4字节的地址空间存储的值是 init_stack代表的地址。 接下来的两个字节 是段选择符值,即将该值存储到SS寄存器中。

表示堆栈段的段选择符。

4、 movl $0x10, %eax #在改变了GDT之后重新加载所有段寄存器,都加载为GDT第3个项内存数据段

mov %ax, %ds

mov %ax, %es

mov %ax, %fs

mov %ax, %gs

lss init_stack, %esp

这段代码有一个疑问,为什么不初始化 cs代码段寄存器,一下是我的个人猜想:

1、因为虽然重新设置了GDT,但是 代码段 在GDT中的 index 并没有改变。 所以不需要再次初始化。 因为代码一直在跑,又没有执行跳转

指令,所以不需要再次初始化 。 但是同时 问题来了, DS 数据段寄存器 为何要初始化,而且还是 0x10, 这次赋值,很诡异。难道说

执行了call 指令后,DS的值发生了改变?? 难道仅仅是 一种好的编程习惯???

2、lss指令 也有类似的问题,应该也不需要初始化,难道也只是为了避免出错而故意再次赋值?只是一种编程习惯?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: