二、进入保护模式--内核加载器LOADER:实模式下内存容量检测、开启保护模式、开启分页模式、加载kernel到内存缓冲区、加载kernel到内存(内存复制函数)->kernel

保护模式

我们刚开机时候进入的都是实模式,对硬件访问没有任何的保护措施,随意修改里面的程序,及其不安全。所以我们之后进入保护模式。
保护模式:cpu扩展、寻址扩展、运行模式扩展、运行模式反转、指令扩展

CPU扩展:

实模式是使用的8086的CPU的16位,保护模式的运行环境变为了32位。所以开机时32位的CPU先处于16位的状态,再转为32位。但是16位也可以访问32位的资源。16位模式下默认操作数位16位,32位模式下默认操作数位32位

寄存器扩展:

除了段寄存器外,通用寄存器、指令指针寄存器、标志寄存器都从原来的16位扩展到32位。AX、BX、CX、DX、SI、DI、BP、SP-->EAX、EBX、ECX、EDX、ESI、EDI、EBP、ESP,FLAGS-->ELAGS,IP-->EIP。

寻址扩展:

实模式下的寻址方式:基址寄存器只能是bx、bp,变址寄存器只能是si、di,bx的默认寄存器是ds、bp的默认寄存器是ss,但是保护模式下,基址寄存器变为所有的32位通用寄存器,变址寄存器变为了除了esp之外的所有32位通用寄存器,偏移量由实模式的16位变为了32位。并且变址寄存器可以乘以一个比例因子,比例因子只能是1、2、4、8。

运行模式反转:

当CPU处于实模式下的16位,依然可以使用32位下的资源,eg:[bits 16] mov eax,0x1234,其中eax是32位的资源,按照常理,CPU操作时候,因为默认16位,所以只会将0x1234读给ax,对eax的前两个字节不管不顾( 保持原值),但是我们的目的是要求CPU也照顾到eax的前两个字节(置0),所以编译器要生成机器码,这需要我们告诉它生成样的机器码,是否要加上前缀来提醒CPU考虑前两个字节。16位下的机器码和32位的机器码是不同的,有时候一个寄存器表示的机器码都不同。所以我们的代码刚开始是在实模式下运行的(默认的),编译器看到32位的资源也会前缀反转去使用它。但是之后我们要进入保护模式32位,关键是还是同一个程序,我们要通知编译器我们进入32位了,看到32资源不需要前缀反转了,所以如下:
[bits 16]是告诉编译器,下面的代码将我编译成16位的机器码,使CPU只考虑16位的资源(寄存器资源、立即数等)。
[bits 32]]是告诉编译器,下面的代码将我编译成32位的机器码,使CPU只考虑32位的资源(寄存器资源、立即数等)。
指令格式:

操作数反转前缀:指令前缀0x66

16位和32位模式之间可以互相使用资源,16位模式下默认操作数位16位,32位模式下默认操作数位32位。但是有时候我们的要求是不一样的,比如要在16位下使用32位的操作数,所以要在机器指令之前加上指令前缀0x66让cpu来识别应该将立即数翻译成0x1234,还是0x0000 1234.
机器码前加上0x66后,假设当前运行模式是16位实模式,操作数大小将变为32位
机器码前加上0x66后,假设当前运行模式是32位保护模式,操作数大小将变为16位
[bits 16] mov eax,0x1234  ;16位模式下按照常规CPU要将0x1234翻译成3412(小端),但eax的32位资源,我们的意思是要考虑eax,所以编译器需要将0x1234反转为32位的34120000。
[bits 32] mov ax,0x1234  ;32位模式下按照常规cpu将0x1234翻译成34120000,但ax是16位资源,我们的意思是只需考虑ax,编译器就翻译为0x3412

寻址方式反转前缀:指令前缀0x67

[bits 16] mov word[eax],0x1234  ;16位模式下,ax是不允许加入到基址寻址中的,编译器将会在机器码前加上67表示段基址加上eax中值将是我们将要访问的内存值。word为伪指令,表示在内存开始出连续写入两个字节大小的数据。
[bits 16] mov dword[eax],0x1234  ;16为模式下,ax是不允许的,所以加上67,但是dword伪指令要在所示内存出连续写入四个字节大小的数据,16位下0x1234默认只翻译位3412,所以还要将3412 0000,所以还要加上66。
[bits 32]mov word [eax],0x1234 ;32位下CPU默认将立即数翻译为32位,但是我们的要求是伪指令word,只要一个字即可,所以加66
[bits 32]mov dword [bx],0x1234  ;32位下CPU默认使用ebx,但是我们的意思是只是用bx,不要使用它的前两个字节,所以加上67。

指令扩展

loop:

 实模式下用cx来储存循环次数,保护模式下要用ecx。每操作一次循环体后cx减1,然后执行loop指令前要拿ecx和0比较(循环条件),等于0则停止循环,不等于0则执行loop指令。相当于for

mul:

实模式下:
如果乘数是8位,则al当作另一个乘数,结果是16位,结果在AX中。
如果乘数是16位,则ax当作另一个乘数,结果是32位,存入高16位在DX中,低16位在AX中。
如果乘数是32位,则eax当作另一个乘数,结果是64位,存入edx:eax中,其中edx是高32位,eax是低32位。
保护模式下:
如果乘数是8位,则al当作另一个乘数,结果是16位,存入ax中。
如果乘数是16位,则ax当作另一个乘数,结果是32位,存入eax中。
如果乘数是32位,则eax当作另一个乘数,结果是64位,存入edx:eax中,其中edx是高32位,eax是低32位。

div:

如果除数是8位,被除数就是16位,位于ax中,结果的商在al,余数在ah
如果除数是16位,被除数就是32位:高16位位于dx,低16位位于ax中,结果的商在ax,余数在dx
如果除数是32位,被除数就是64位:高32位位于edx,低32位位于eax中,结果的商在eax,余数在edx

push:

不管在实模式还是保护模式都可以同时处理16位和32位的数据。

push 立即数

push 寄存器

push 内存

push 立即数:
实模式下:
压入8位立即数,因为默认操作数是16位,CPU位将其扩展为16位后,将其入栈。sp-2

压入16位立即数,cpu会将其直接入栈。sp-2

压入32位立即数,cpu会将其直接入栈。sp-4

保护模式下:

压入8位立即数,因为默认操作数是32位,CPU位将其扩展为32位后,将其入栈,sp-4

压入16位立即数,cpu会将其直接入栈,sp-2

压入32位立即数,cpu会将其直接入栈,sp-4

push 寄存器:
实模式下:

压入段寄存器:cs、ds、es、fs、gs、ss,,按照当前默认操作数大小压入,sp-2

压入通用寄存器,如果压入的16位的,sp-2,如果压入32位的,sp-4<

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值