32处理器起源于1985年10月推出的80386,寄存器,数据总线,算数逻辑单元都是32位,提供32位地址线,可以访问4G内存。80386兼容8086指令。
保护模式:将内存的每个程序隔离,避免程序之间互相影响。
x86 : Intel公司86系列处理器的统称。
IA-32,x86-32: 英特尔32位架构
从16位到32位处理器寄存器的扩展和扩充(32位处理器高16位不能独立使用):
8086 16位通用寄存器 | 80386 32位通用寄存器 |
---|---|
AX16位{AH高8,Al低8} | EAX 32位 |
BX16位{BH高8,Bl低8} | EBX 32位 |
CX16位{CH高8,Cl低8} | ECX 32位 |
DX16位{DH高8,Dl低8} | EDX 32位 |
SI16位 | ESI 32位 |
DI | EDI |
BP | EBP |
SP | ESP |
寄存器混合使用案例:
mov edx ,0xf000c000
mov dx,0 ;edx=0xf000 0000
add edx,0xcccc ;edx=0xf000cccc
实模式 | 保护模式 |
---|---|
只和真实内存地址进行交互,程序内存布局是真实物理内存布局 | 内存的真实布局进行了转换 |
32位指令指针寄存器的扩展: EIP(保护模式下才会用EIP)32位{IP低16位,在实模式下只用ip处理指令},标志位寄存器扩展:EFLAGS{低16位FLAGS}
32位新增加的段寄存器FS,GS,总的段寄存器CS\DS\ES\FS\GS\SS,段寄存器长度未变16位;实模式下段寄存器用法不变(用来保存逻辑段地址,逻辑段地址左移4位加偏移地址,形成20位地址来寻址),保护模式下,段寄存器用法发生变化。
32位处理器内存访问概况:
程序所使用的段需要提前分配,登记在一个表中叫做描述符表,记录了每个段的起始地址,段的长度等基本信息,段的长度没有限制,描述符内段的起始地址可以是32位的任意地址,段的长度最大可以使4G字节(假如段起始是0,段长度是4G); 在保护模式下段寄存器不在用于保存逻辑段地址,而是描述符的选择子,用来从描述符中选择一个描述符,通过描述符,处理器取出段基地址+程序内给出的段内偏移地址形成完整的内存地址,偏移地址32位没有限制。
32处理器寻址概述:
寄存器寻址:
mov ah,dh ; 寄存器寻址,寄存器宽度8位,在32位处理器依然有效 mov ax,dx ; 寄存器寻址,寄存器宽度16位,在32位处理器依然有效 mov eax,edx ;寄存器寻址,寄存器宽度32位
内存寻址,如果指令中包含了内存寻址,一定是一个段内偏移地址:有效地址(Effective address :EA),默认段地址ds
32位:基址寄存器+变址寄存器*(1、2、4、8比例因子)+8位或32位偏移量,无论是16位还是32位,不允许使用栈指针寄存器sp提供有效地址(ESP可以),下图mov ax,[sp]非法
案例:16位写显存显示字符:
mov ax,0xb000
mov ds,ax
mov bx,0x8000
mov byte [bx+0x00],';'
mov byte [bx+0x01],0x07
mov byte [bx+0x02],')'
mov byte [bx+0x03],0x07
jmp $
times 510-($-$$) db 0
db 0x55,0xaa
使用eax代替bx(16位处理器不能使用ax形成有效地址,32位处理器可以使用eax形成有效地址)
mov ax,0xb000
mov ds,ax
mov eax,0x8000
mov byte [eax+0x00],';'
mov byte [eax+0x01],0x07
mov byte [eax+0x02],')'
mov byte [eax+0x03],0x07
jmp $
times 510-($-$$) db 0
db 0x55,0xaa
x86流水线技术,pipline
下图,每条指令执行都要3个步骤,假设每个步骤需要一个时钟周期,3个指令执行需要9个周期,流水线执行需要5个周期。
高速缓存技术
乱序执行技术 out of order execution
寄存器重命名技术
分支目标预测技术branch Prediction (当处理器遇到转移指令时,需要清空flush流水线),分支目标缓存器BTB
保护模式下每个程序有自己的特权级0,1,2,3 ;0级最高-操作系统,3级最低-用户程序,因为操作系统权限最高,可以分配内存、加载用户程序、设置用户程序特权级别、调度用户程序执行等等。程序由代码段、数据段、栈段组成(包括操作系统程序,用户程序),操作系统会等级每个程序所使用的段,包括段的起始内存位置、段的长度等信息,如果一个程序的特权级很低,它只能访问自己的段
后面的内容包括:
全局描述符表GDT 段描述符的各个组成部分以及他们的含义和作用 认识描述符表寄存器GDTR、控制器CR0和段选择子 进入32位保护模式的方法和步骤 保护模式下的程序调试 x86新指令lgdt(load GDT)
和一个段有关的信息需要8个字节来描述,称为段描述符Segment Descriptor,每个段需要一个段描述符,需要在内存开辟一段空间存储段描述符,当所有段描述符在这里集中存放形成的表格叫做描述符表,用来管理所有的用户程序,在进入保护模式前要先定义GDT,为了跟踪GDT,在处理器内有一个48位寄存器GDTR(保存了GDT的起始线性地址和GDT的界限值,界限值是表内最后一个字节相对于起始值的偏移量=<表的总字节数减1>,所以表最大为65536个字节即64kB,一个描述符8个字节,所以可以在GDT中定义8192个描述符),由于实模式下只能访问1M内存,GDT通常定义下0-1M内的内存空间。
描述符分类:一类--存储器的段描述符,用于描述一般的代码段或者数据段(栈段也是数据段),另一类是系统描述符,用于描述系统运行控制相关的内容,包括:系统的段描述符、门描述符(与程序运行有关的逻辑结构,过程调用、中断处理等)
描述符的作用:每个描述符用于描述一个代码段,或者数据段,或者过程入口信息等,描述符是这些对象的索引标签,通过描述符可以定位找到这些对象.
如上图所示,每个描述符占8字节64位,从0-63,描述符位44是S位,S=0是系统描述符,type段用来指定系统段类型或者门的类型。
存储器的段描述符-段的类型和段的特权级:
在S=1时,当前描述符是存储器的段描述符,TYPE(决定存储器的段类型)的位11是执行位X(executable),X=0表示不可执行是数据段。E(expand)扩展位,表示扩展方向E=0,表示段向上扩展,是普通数据段,E=1从高地址向低地址扩展是栈段;W位是段的读写位,是否可写,W=0不允许写入,只能读,W=1表示段可以正常写入。
X=1,该描述符表示是一个可执行的段,即是代码段,在这种情况下另外三位叫做C、R、A位,C是特权级依从的段,C=0表示非依从的代码段,只有特权级相同的程序才能直接转移到这个段内执行;C=1表示依从的代码段,特权级低的程序可以直接转移到段内执行。没有特殊要求C位通常清零。R位指示代码段是否可以被读出,为了防止程序被破坏代码段是不能被写入的,R决定代码段是否能像数据一样被读取,R=0不能读出,R=1可以读出。A位accessed是否已访问过,无论X是0、1,该描述符所描述的段是否使用过,描述符创建后A位清零,访问后置1,清零由操作系统负责,内存紧张时操作系统将不经常用的段退避到磁盘上,从而实现虚拟内存管理。如下图所示:
描述符的高双字,位13-14两表示段的特权级,组合是00 01 10 11,代表 0,1,2,3 四种特权级别,如下图所示:
描述符中有20位的段界限(段边界),低双字的位的0-15 ,高双字的位 16-19,20位的段界限限制段的扩展范围。对于向上扩展的段,段界限是最大偏移量,超过最大界限会被处理器阻止出现异常中断,段的大小是段界限+1 ; X=0且E=1向下扩展的数据段(通常用作栈段),使用SP时,最大值FFFF,使用ESP时ESP最大值FFFFFFFF,此时段界限是指针所不允许的最小值,等于或小于这个值会引发处理器中断,如果指定的段界限是0,并不是至段大小是0,相反段此时是最大值
G位,段界限的单位,G=0是段界限以字节为单位,G=1段界限以4K字节为单位(G=1时 ,实际使用的段界限= 描述符中的段界限+0x1000+0xFFF)
P位,段存在位,P=0 表示段不存在(当内存资源紧张时,将不常用的段换出内存放入磁盘),当通过描述符访问内存中的段时,如果p=0,产生异常中断,该中断处理过程由操作系统提供,负责从硬盘将段换回内存,并将p位置1,在多用户多任务系统中是常用任务策略。
L位: 64位代码标段志位,保留此位给64位处理器使用,用于指示64位的代码段,(32位处理器)目前将这一位置0即可
描述符D/B位(操作尺寸/栈上部边界) ,高双字的位22,用于说明段时按16位(B/D位=0)进行操作还是按32位(B/D位=1)进行操作,例如对于向下扩展的段界限来说,用于指示0xffff还是0xffffffff,使用SP进行操作还是ESP进行操作
AVL位(Available可自由使用的保留位),高双字的20位。
在全局描述符表GDT中安装存储器的段描述符
下图段的基地址是0x000B 8000,段界限是0x0FFFF=64k,P位1,说明段存在,DPL=0特权级,S=1说明是存储器的段,X=0说明是数据段,E=0向上扩展,W=1这个段可写,A初始化为0,
,
此描述符在内存中的分布:
通过上面的代码可以创建GDT表,下面要加载全局描述符表线性地址和全局描述符表边界到48位的GDTR寄存器,使用lgdt指令
lgdt m ; m的起始地址往后是一个48位的操作数,这个操作数分为2部分:第一部分是GDT的界限值,长度1个字;第二部分是GDT线性地址,长度是2个字
开启处理器的第21根地址线A20
in al,0x92 ;南桥芯片内的端口
or al,0000_0010B ;二进制数据,将al位1置1
out 0x92,al ;会写数据,打开A20
通过设置控制寄存器CR0(Control Register:CR,因为处理器还有CR1,cr2,cr3等,所以命名CR0)的PE位,开启保护模式,(在调试器中观察gdtr和cr0). CR0是32位,位0是PE位,PE=1进入保护模式。
cli ;保护模式下中断机制尚未建立,应
;禁止中断
mov eax,cr0
or eax,1
mov cr0,eax ;设置PE位
段寄存器的描述符高速缓存器,用于保护模式下得内存访问。在保护模式下处理器的很多工作方式发生变化,在保护模式下CS\DS\ES\FS\GS\SS不再叫段寄存器,而叫段选择器,这6个寄存器各自增加了1个不可见的部分,叫做描述符高速缓存器。描述符高速缓存器存放段的线性基地址、段界限和访问控制属性。在实模式下段选择器内容是逻辑段地址,在保护模式下,段选择器内容是段描述符的选择子,简称选择子。
段选择子 (Segment Selector:SS),由三部分组成,第一部分 描述符索引用来在描述符表中选择一个段描述符,2的13次方=8192,可以选择8192个段描述符;第二部分TI,Table Indicator:TI表指示器 ,描述符表的指示器,TI=0时表示要选择的描述符在全局描述符表GDT中,TI=1描述符在LDT中,第三部分位0和位1是RPL,请求特权级。为了访问一个段,要将段选择子传送到段选择器,一旦用段选择子改变了段选择器,处理器会立刻用段选择子去描述符表中取出描述符,将描述符的内容传送到描述符高速缓存器中,从此处理器就用高速缓存器中的线性基地址+段内偏移来访问内存,而不是用段选择器。
加载数据段选择子的案例:
;选择GDT的第二个描述符
mov cx,00000000000_01_000B
mov ds,cx
加载段选择子处理器处理过程如下:
80286的16位保护模式
80286寄存器基本与8086相同,AX\BX\CX\DX\Si\DI\SP\BP\IP\CS\DS\ES\SS,但是80286由24根地址线,为了支持超过1M内存,支持多用户多任务,加强对程序的保护,80286引入了保护模式
下图显示描述符基地址是24位,80286的段寄存器只有4个,但是80286增加了描述符高速缓存器(包含段的线性基地址、界限和属性),
16位处理器指令操作尺寸8、16,32位处理器指令操作尺寸8、16、32
x86处理器机器指令格式,操作码1-3个字节
F4 hlt FA cli FD std C3 ret CC int3
操作码1-3个字节+立即数1/2/4个字节(注意立即数低端字节序)
B0 03 mov al,3 B9 0300 mov cx,3 BA 03000000 mov edx,3
操作码参考x86架构软件开发手册卷一-基本架构,卷二-指令集参考,卷三-系统编程指南
x86处理器指令格式,寻址方式ModR/M和偏移量部分。
有些指令比较复杂,如需要在2个寄存器之间或者寄存器内存之间进行操作,此时在操作码的后面需要一个寻址方式部分ModR/M(长度1个字节)
88C8 mov al,cl 8B07 mov ax,[bx] 8B08 mov cx,[bx+si]
ModR/M 的组成(mod和r/m字段配合使用)
67位 mod 345位 reg/opcode 012位 r/m
x86处理器指令格式--寻址方式SIB
32位寻址方式如下图:
上图寻址方式的指令格式 操作码1-3+ modR/m 1个字节 + SIB 1个字节
SIB字段的格式:
x86处理器指令格式--前缀部分(如段超越前缀,一个指令最多可以有4个前缀,每个前缀1个字节)
机器码 | 指令 |
---|---|
8917 | mov [bx],dx |
2E8917 | mov [cs:bx],dx |
A5 | movsw |
F3A5 | rep movsd |
16位操作尺寸,32位操作尺寸,处理器默认操作尺寸和相关指令前缀
不同的指令可能有相同的机器码(如果解决这个问题,通过默认操作尺寸增加机器码前缀)如下图:
32位处理器支持16位和32位操作尺寸。 但是,在同一时刻,处理器只能按一种操作尺寸工作,要么选16位操作尺寸,要么选32位操作尺寸,这叫做处理器的默认操作尺寸。
伪指令bits生成16位和32位模块
bits 16 ;(可以用[]括起来[bits 16]) 告诉编译器假定后面的操作尺寸是多少(同一条指令不通的bits下编译出来的操作码不同)。要求程序开发人员清除程序在什么情况下执行,处理器的默认操作尺寸是多少。
描述符和段描述符高速缓存器的D位。
如何知道处理器当前默认的操作尺寸,如何改变处理器的默认操作尺寸,在段描述符高双字22位,位D/B位。对于S=1,x=1 这一位是D位,D=0是16位操作尺寸,D=1表示32位操作尺寸。通过高速缓存器的内容D位,可以知道处理器当前默认的操作尺寸。
进入保护模式后,立即切换到32位模块并使用32位默认操作尺寸。 直接绝对远转移指令:在实模式下与保护模式下不同
;文件说明:硬盘主引导扇区代码
;设置堆栈段和栈指针
mov ax,cs
mov ss,ax
mov sp,0x7c00
;计算GDT所在的逻辑段地址
mov ax,[cs:gdt_base+0x7c00] ;低16位
mov dx,[cs:gdt_base+0x7c00+0x02] ;高16位
mov bx,16
div bx
mov ds,ax ;令DS指向该段以进行操作
mov bx,dx ;段内起始偏移地址
;创建0#描述符,它是空描述符,这是处理器的要求
mov dword [bx+0x00],0x00
mov dword [bx+0x04],0x00
;创建#1描述符,保护模式下的代码段描述符
mov dword [bx+0x08],0x7c0001ff
mov dword [bx+0x0c],0x00409800
;创建#2描述符,保护模式下的数据段描述符(文本模式下的显示缓冲区)
mov dword [bx+0x10],0x8000ffff
mov dword [bx+0x14],0x0040920b
;创建#3描述符,保护模式下的堆栈段描述符
mov dword [bx+0x18],0x00007a00
mov dword [bx+0x1c],0x00409600
;初始化描述符表寄存器GDTR
mov word [cs: gdt_size+0x7c00],31 ;描述符表的界限(总字节数减一)
lgdt [cs: gdt_size+0x7c00]
in al,0x92 ;南桥芯片内的端口
or al,0000_0010B ;二进制数据,将al位1置1
out 0x92,al ;会写数据,打开A20
cli ;保护模式下中断机制尚未建立,应
;禁止中断
mov eax,cr0
or eax,1
mov cr0,eax ;设置PE位
;以下进入保护模式... ...
jmp dword 0x0008:flush ;16位的描述符选择子:32位偏移
;清流水线并串行化处理器
[bits 32]
flush:
mov cx,00000000000_10_000B ;加载数据段选择子(0x10)
mov ds,cx
;以下在屏幕上显示"Protect mode OK."
mov byte [0x00],'P'
mov byte [0x02],'r'
mov byte [0x04],'o'
mov byte [0x06],'t'
mov byte [0x08],'e'
mov byte [0x0a],'c'
mov byte [0x0c],'t'
mov byte [0x0e],' '
mov byte [0x10],'m'
mov byte [0x12],'o'
mov byte [0x14],'d'
mov byte [0x16],'e'
mov byte [0x18],' '
mov byte [0x1a],'O'
mov byte [0x1c],'K'
;以下用简单的示例来帮助阐述32位保护模式下的堆栈操作
mov cx,00000000000_11_000B ;加载堆栈段选择子
mov ss,cx
mov esp,0x7c00
mov ebp,esp ;保存堆栈指针
push byte '.' ;压入立即数(字节)
sub ebp,4
cmp ebp,esp ;判断压入立即数时,ESP是否减4
jnz ghalt
pop eax
mov [0x1e],al ;显示句点
ghalt:
hlt ;已经禁止中断,将不会被唤醒
;-------------------------------------------------------------------------------
gdt_size dw 0
gdt_base dd 0x00007e00 ;GDT的物理地址
times 510-($-$$) db 0
db 0x55,0xaa
mov ds,ax ; 此指令任何时候(16位和32位)机器码都一样 mov ds,eax
保护模式下修改段寄存器的保护机制:1、将一个描述符选择子带入段选择器,此时要检查带入值的合法性,2、用选择子选择一个描述符并传送到高速缓存器,此时要检查描述符的正确性和完成性。
xchg al,ah ;交换指令 exchange,xchg r/m ,r/m ,两个操作数不能同时为内存地址。操作数长度一致。 xchg al,ah xchg ecx,edx xchg xc,[0x7e00]
字符串跑冒泡排序并在屏幕显示:
;文件说明:硬盘主引导扇区代码
;设置堆栈段和栈指针
mov eax,cs
mov ss,eax
mov sp,0x7c00
;计算GDT所在的逻辑段地址
mov eax,[cs:pgdt+0x7c00+0x02] ;GDT的32位线性基地址
xor edx,edx
mov ebx,16
div ebx ;分解成16位逻辑地址
mov ds,eax ;令DS指向该段以进行操作
mov ebx,edx ;段内起始偏移地址
;创建0#描述符,它是空描述符,这是处理器的要求
mov dword [ebx+0x00],0x00000000
mov dword [ebx+0x04],0x00000000
;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间
mov dword [ebx+0x08],0x0000ffff ;基地址为0,段界限为0xfffff
mov dword [ebx+0x0c],0x00cf9200 ;粒度为4KB,存储器段描述符
;创建保护模式下初始代码段描述符
mov dword [ebx+0x10],0x7c0001ff ;基地址为0x00007c00,512字节
mov dword [ebx+0x14],0x00409800 ;粒度为1个字节,代码段描述符
;创建以上代码段的别名描述符
mov dword [ebx+0x18],0x7c0001ff ;基地址为0x00007c00,512字节
mov dword [ebx+0x1c],0x00409200 ;粒度为1个字节,数据段描述符
mov dword [ebx+0x20],0x7c00fffe ;基地址0x00007c00 ,向下扩展,界限0xffffe,粒度4KB,数据段描述符
mov dword [ebx+0x24],0x00cf9600
;初始化描述符表寄存器GDTR
mov word [cs: pgdt+0x7c00],39 ;描述符表的界限
lgdt [cs: pgdt+0x7c00]
in al,0x92 ;南桥芯片内的端口
or al,0000_0010B
out 0x92,al ;打开A20
cli ;中断机制尚未工作
mov eax,cr0
or eax,1
mov cr0,eax ;设置PE位
;以下进入保护模式... ...
jmp dword 0x0010:flush ;16位的描述符选择子:32位偏移,jmp会隐式修改段寄存器cs
[bits 32]
flush:
mov eax,0x0018
mov ds,eax
mov eax,0x0008 ;加载数据段(0..4GB)选择子
mov es,eax
mov fs,eax
mov gs,eax
mov eax,0x0020 ;0000 0000 0010 0000
mov ss,eax
xor esp,esp ;ESP <- 0
mov dword [es:0x0b8000],0x072e0750 ;字符'P'、'.'及其显示属性
mov dword [es:0x0b8004],0x072e074d ;字符'M'、'.'及其显示属性
mov dword [es:0x0b8008],0x07200720 ;两个空白字符及其显示属性
mov dword [es:0x0b800c],0x076b076f ;字符'o'、'k'及其显示属性
;开始冒泡排序
mov ecx,pgdt-string-1 ;遍历次数=串长度-1
@@1:
push ecx ;32位模式下的loop使用ecx
xor bx,bx ;32位模式下,偏移量可以是16位,也可以
@@2: ;是后面的32位
mov ax,[string+bx]
cmp ah,al ;ah中存放的是源字的高字节
jge @@3
xchg al,ah
mov [string+bx],ax
@@3:
inc bx
loop @@2
pop ecx
loop @@1
mov ecx,pgdt-string
xor ebx,ebx ;偏移地址是32位的情况
@@4: ;32位的偏移具有更大的灵活性
mov ah,0x07
mov al,[string+ebx]
mov [es:0xb80a0+ebx*2],ax ;演示0~4GB寻址。
inc ebx
loop @@4
hlt
;-------------------------------------------------------------------------------
string db 's0ke4or92xap3fv8giuzjcy5l1m7hd6bnqtw.'
;-------------------------------------------------------------------------------
pgdt dw 0
dd 0x00007e00 ;GDT的物理地址
;-------------------------------------------------------------------------------
times 510-($-$$) db 0
db 0x55,0xaa
bswap r ;反转寄存器的操作数
cpuid 指令
条件传送指令:
cmovne 不相等则传送(cmovcc指令族)
cmov.. r, r/m
SGDT m ;SGDT指令 Store Global Descriptor Table register,将全局描述符寄存器GDTR内容读出的内存M, m必须有6个字节的空间.
movzx movsx
字符串比较指令:
cmpsb 按字节进行比较 cmpsw 按字进行比较 cmpsd 按双字进行比较 cmpsq 按四字进行比较
当前处理器默认的操作尺寸 | 目的串 | 源串 |
---|---|---|
16 | ES:DI | DS:SI |
32 | ES:EDI | DS:ESI |
64 | ES:RDI | DS:RSI |
串比较指令的重复前缀,串比较的方向(cmpsb从源串地址和目的串地址各取出一个字节比较)
rep cmpsb rep cmpsw rep cmpsd rep cmpsq
前缀rep的重复次数
默认操作尺寸 | rep前缀使用的计数器 |
---|---|
16 | cx |
32 | ecx |
64 | rcx |
rep cmpsb 必须将cx/ecx/rcx设置为串的总字节数 rep cmpsw 必须将cx/ecx/rcx设置为串的总字节数/2 rep cmpsd 必须将cx/ecx/rcx设置为串的总字节数/4 rep cmpsq 必须将cx/ecx/rcx设置为串的总字节数/8
repe 相等则重复 repz 为0则重复 repne 不相等则重复 repnz 不为0则重复
重复前缀 | 终止条件 |
---|---|
rep | cx/ecx/rcx=0 |
repe/repz | cx/ecx/rcx=0 并且zf=0 |
repne/repnz | cx/ecx/rcx=0 并且zf=1 |
案例: repe cmpsw ,如果比较结果标志位ZF=1,说明相等,(cx/ecx/rcx 减1)则再次执行repe cmpsw,如果比较结束cx/ecx/rcx=0且ZF=1,说明2个字符串相等;再重复执行的过程中有2个字符串不相等,ZF=0,比较过程提前终止,两个串不同。
串的比较方向取决于标志寄存器DF位。
串比较的过程:
以十六进制形式显示一个双字、PUSHAD\POPAD和XLAT指令
pushad 指令意思是 push all double ,压入全部的双字寄存器,压栈顺序EAX-ECX-EDX-EBX-ESP-EBP-ESI-EDI
popad 指令的意思是pop all double,从栈中弹出双字寄存器,出栈顺序 EDI-ESI-EBP-废弃-EBX-EDX-ECX-EAX
为了是数值转换成可显示的字符编码,可使用xlat查表指令:
操作系统有自己的数据段-栈段-代码段,有全局GDT;每个用户程序有自己的数据段-栈段-代码段,有自己独立的LDT。每个用户程序还要有一个特殊的内存段TSS任务状态段(task status segment),用来保存改程序的相关信息(多任务操作系统,从当前执行的程序切换到其他程序需要保存当前任务的状态信息【段寄存器的值、指令指针寄存器的值、通用寄存器的值等等】,等下次程序运行时,再从tss中恢复)
任务控制块=Task Control Block :TCB
push imm8 ;push byte 0x55 push imm16 ;push word 0x55 push imm32 ;push dword 0x55
带参数的ret 指令返回调用者