汇编实例解析--保护模式下屏幕显示,保护模式下冒泡排序

1.1.保护模式下屏幕显示

        保护模式,32位下,屏幕显示

         ; 刚刚进入主引导程序时候,
         ; 主引导程序被加载到物理位置0x0000:0x7c00开始的地方
         ; cx此时的内容是0x0000
         mov ax,cs      
         ; 设置栈段
         mov ss,ax 
         ; 设置栈指针,初始时候指向高地址
         mov sp,0x7c00 

         ; 到指定物理内存位置取出2字节
         mov ax,[cs:gdt_base+0x7c00]  
         ; 到指定物理内存位置取出2字节
         mov dx,[cs:gdt_base+0x7c00+0x02] 
         mov bx,16        
         div bx ; dx:ax / 16,商ax,余数dx           
         ; 这是指定物理内存位置4字节构成的32位地址的段地址
         mov ds,ax  
         ; dx作为余数,其实是4字节对应32位地址的段内偏移
         mov bx,dx  

         ; 将指定物理内存位置4字节设置为0x00
         mov dword [bx+0x00],0x00
         ; 将指定物理内存位置4字节设置为0x00
         mov dword [bx+0x04],0x00  

         ; 8字节数据展开
         ; 0x00 0x40 0x98 0x00 0x7c 0x00 0x01 0xff
         ; 高位<-----低位
         ; 段基地址31~24 G D/B L AVL 段界限19~16 P DPL S TYPE 段基地址23~16 段基地址15~0 段界限15~0
         ; 段基地址:0x00 0x00 0x7c 0x00,意思是段基地址为0x0000 7c00
         ; G为0,意思是段界限是字节为单位
         ; D/B为1,意思是段内的数据是32位的
         ; L为0,保留
         ; AVL为0,保留给软件
         ; 段界限0x0 0x01 0xff,0x001ff
         ; P为1,表示段的内容已经在物理内存了
         ; DPL为0,段的特权级
         ; S为1,非系统段
         ; TYPE为0x8,表示段可执行的代码段
         ; 将指定物理内存位置4字节设置为指定内容
         mov dword [bx+0x08],0x7c0001ff     
         ; 将指定物理内存位置4字节设置为指定内容
         mov dword [bx+0x0c],0x00409800     
         
         ; 8字节数据展开
         ; 0x00 0x40 0x92 0x0b 0x80 0x00 0xff 0xff
         ; 高位<-----低位
         ; 段基地址31~24 G D/B L AVL 段界限19~16 P DPL S TYPE 段基地址23~16 段基地址15~0 段界限15~0
         ; 段基地址:0x00 0x0b 0x80 0x00,意思是段基地址为0x000b 8000
         ; G为0,意思是段界限是字节为单位
         ; D/B为1,意思是段内的数据是32位的
         ; L为0,保留
         ; AVL为0,保留给软件
         ; 段界限0x0 0xff 0xff,0x0ffff,对于向上扩展的段,这个代表了段内尺寸-1
         ; P为1,表示段的内容已经在物理内存了
         ; DPL为0,段的特权级
         ; S为1,非系统段
         ; TYPE为0x2,表示段可读,可写数据段
         mov dword [bx+0x10],0x8000ffff     
         mov dword [bx+0x14],0x0040920b     
         
         ; 8字节数据展开
         ; 0x00 0x40 0x96 0x00 0x00 0x00 0x7a 0x00
         ; 高位<-----低位
         ; 段基地址31~24 G D/B L AVL 段界限19~16 P DPL S TYPE 段基地址23~16 段基地址15~0 段界限15~0
         ; 段基地址:0x00 0x00 0x00 0x00,意思是段基地址为0x0000 0000
         ; G为0,意思是段界限是字节为单位
         ; D/B为1,意思是段内的数据是32位的
         ; L为0,保留
         ; AVL为0,保留给软件
         ; 段界限0x0 0x7a 0x00,0x07a00,对向下扩展的段,这个代表了段的物理位置的下限
         ; 只要栈顶指针大于等于这个值,栈顶指针都是有效了。否则,就是无效的。
         ; P为1,表示段的内容已经在物理内存了
         ; DPL为0,段的特权级
         ; S为1,非系统段
         ; TYPE为0x6,表示段可读,可写向下扩展的栈段
         mov dword [bx+0x18],0x00007a00
         mov dword [bx+0x1c],0x00409600
         
         ; 将指定物理内存位置2字节设置为指定内容
         mov word [cs: gdt_size+0x7c00],31  
         ; 将指定物理内容位置处6字节传递给处理器
         ; 这样处理器就知道了程序的gdt的起始物理位置,gdt区域的尺寸
         lgdt [cs: gdt_size+0x7c00] 
     
         ; 从0x92读入1字节到al
         in al,0x92           
         ; 将读出字节第1位【从0计算】设置为1             
         or al,0000_0010B          
         ; 将修改后内容写入0x92
         ; 这样做,可以让进程可以使用32位地址线来表示32位地址空间
         ; 未这样做的时候,32位地址线只有低20位存储有效地址        
         out 0x92,al                       
         
         ; 禁止中断
         cli       
         ; 读取cr0寄存器内容                        
         mov eax,cr0 
         ; 设置最低位为1
         or eax,1 
         ; 这样将使得进程进入保护模式运行
         mov cr0,eax                     
         ; 需要用一个跳转进行实模式和保护模式的过渡
         ; 两个模式主要区别是:
         ; 实模式访问数据,访问代码采用段地址*0x10+段内偏移来实现。段寄存器存储的就是段地址。段缺乏保护。
         ; 保护模式,每个段首先通过一个64位描述符描述符其起始位置,尺寸,其他属性。段寄存器存储的是段选择子。
         ; 通过选择子找到段的64位描述符。【前提是已经使用lgdt告知处理器段描述符的信息】
         ; 从64位描述符中提取32位起始地址+偏移地址来访问数据,访问代码。
         ; 且对段的访问存在保护。  
         ; 0x0008,对应的段选择子内索引是1【从0开始】
         jmp dword 0x0008:flush          
         [bits 32] 
    flush:
         mov cx,00000000000_10_000B     
         ; 对应的段选择子内索引是2   
         mov ds,cx 
         ; 设置物理内存位置值
         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'
         ; 上述设置了显存,达到在屏幕显示字符效果
         mov cx,00000000000_11_000B      
         ; 对应的段选择子内索引是3  
         mov ss,cx 
         ; 栈段一开始偏移位于高地址处
         ; esp合法的变动范围是[0x7a00, 0x7c00]
         mov esp,0x7c00 

         mov ebp,esp   
         ; 入栈存放1字节
         push byte '?'  
         ; 将ebp减去4
         sub ebp,4
         ; 比较栈顶与ebp是否相等
         cmp ebp,esp    
         ; 不相等则跳转
         jnz ghalt     
         ; 相等则出栈,得到4字节数据                     
         pop eax 
         ; 取其中1字节设置到指定物理内存位置
         mov [0x1e],al 
  ghalt:    
         ; 停机,等待被中断唤醒。
         hlt 
         ; gdt尺寸
         gdt_size         dw 0
         ; gdt起始物理内存位置
         gdt_base         dd 0x00007e00  
         ; 填充  
         times 510-($-$$) db 0
                          ; 引导块完整性要求
                          db 0x55,0xaa

1.2.保护模式下冒泡排序

        保护模式,32位下冒泡排序

         ; 进入主引导程序
         ; 此时程序在内存0x0000:0x7c00开始的一块位置
         ; cs此时是0x0000 
         mov eax,cs      
         ; 设置栈段 
         mov ss,eax
         ; 设置栈段指针,初始位于最大地址处 
         mov sp,0x7c00 
       
         ;用4字节物理内存数据设置eax
         mov eax,[cs:pgdt+0x7c00+0x02]
         ; edx设置为0  
         xor edx,edx 
         mov ebx,16 
         ; edx:eax / 16
         ; 商在eax,余数在edx
         div ebx 
         ; 用商设置dx,这是4字节物理地址的段地址
         mov ds,eax 
         ; 余数设置ebx,这是4字节物理地址的段内偏移
         mov ebx,edx 
         
         mov dword [ebx+0x00],0x00000000 
         ; 将指定物理内存位置4字节设置为指定值
         mov dword [ebx+0x04],0x00000000 
       
         ; 8字节数据展开
         ; 0x00 0xcf 0x92 0x00 0x00 0x00 0xff 0xff
         ; 高位<-----低位
         ; 段基地址31~24 G D/B L AVL 段界限19~16 P DPL S TYPE 段基地址23~16 段基地址15~0 段界限15~0
         ; 段基地址:0x00 0x00 0x00 0x00,意思是段基地址为0x0000 0000
         ; G为1,意思是段界限是页为单位
         ; D/B为1,意思是段内的数据是32位的
         ; L为0,保留
         ; AVL为0,保留给软件
         ; 段界限0xf 0xff 0xff,0xfffff,
         ; P为1,表示段的内容已经在物理内存了
         ; DPL为0,段的特权级
         ; S为1,非系统段
         ; TYPE为0x2,表示段可读,可写的数据段
         mov dword [ebx+0x08],0x0000ffff 
         mov dword [ebx+0x0c],0x00cf9200 
         
         ; 8字节数据展开
         ; 0x00 0x40 0x98 0x00 0x7c 0x00 0x01 0xff
         ; 高位<-----低位
         ; 段基地址31~24 G D/B L AVL 段界限19~16 P DPL S TYPE 段基地址23~16 段基地址15~0 段界限15~0
         ; 段基地址:0x00 0x00 0x7c 0x00,意思是段基地址为0x0000 7c00
         ; G为0,意思是段界限是字节为单位
         ; D/B为1,意思是段内的数据是32位的
         ; L为0,保留
         ; AVL为0,保留给软件
         ; 段界限0x0 0x01 0xff,0x001ff,
         ; P为1,表示段的内容已经在物理内存了
         ; DPL为0,段的特权级
         ; S为1,非系统段
         ; TYPE为0x8,表示段是只执行的代码段
         mov dword [ebx+0x10],0x7c0001ff  
         mov dword [ebx+0x14],0x00409800 
        
         ; 8字节数据展开
         ; 0x00 0x40 0x92 0x00 0x7c 0x00 0x01 0xff
         ; 高位<-----低位
         ; 段基地址31~24 G D/B L AVL 段界限19~16 P DPL S TYPE 段基地址23~16 段基地址15~0 段界限15~0
         ; 段基地址:0x00 0x00 0x7c 0x00,意思是段基地址为0x0000 7c00
         ; G为0,意思是段界限是字节为单位
         ; D/B为1,意思是段内的数据是32位的
         ; L为0,保留
         ; AVL为0,保留给软件
         ; 段界限0x0 0x01 0xff,0x001ff,
         ; P为1,表示段的内容已经在物理内存了
         ; DPL为0,段的特权级
         ; S为1,非系统段
         ; TYPE为0x2,表示段是可读,可写的数据段
         mov dword [ebx+0x18],0x7c0001ff
         mov dword [ebx+0x1c],0x00409200 

         ; 8字节数据展开
         ; 0x00 0xcf 0x96 0x00 0x7c 0x00 0xff 0xfe
         ; 高位<-----低位
         ; 段基地址31~24 G D/B L AVL 段界限19~16 P DPL S TYPE 段基地址23~16 段基地址15~0 段界限15~0
         ; 段基地址:0x00 0x00 0x7c 0x00,意思是段基地址为0x0000 7c00
         ; G为1,意思是段界限是页为单位
         ; D/B为1,意思是段内的数据是32位的
         ; L为0,保留
         ; AVL为0,保留给软件
         ; 段界限0xf 0xff 0xfe,0xffffe,
         ; P为1,表示段的内容已经在物理内存了
         ; DPL为0,段的特权级
         ; S为1,非系统段
         ; TYPE为0x6,表示段是可读,可写的向下扩展的栈段
         ; 栈段的段界限以页为单位下
         ; 如何确定栈地址和合法范围
         ; 对于ESP有以下限制
         ; 描述符中的段界限值*0x1000 + 0xFFF + 1 <= [ESP-操作数长度] <= 0xFFFFFFFF
         ; 实际的物理地址 = 栈基地址+ESP
         mov dword [ebx+0x20],0x7c00fffe 
         mov dword [ebx+0x24],0x00cf9600 
         
         ; 将指定物理内存位置2字节设置为39
         mov word [cs: pgdt+0x7c00],39 
         ; 将gdt起始物理内存位置和尺寸告知处理器
         lgdt [cs: pgdt+0x7c00] 
      
         in al,0x92 
         or al,0000_0010B 
         ; 打开a20地址线,
         ; 此后,进程可使用32为地址空间
         out 0x92,al 
       
         ; 禁止中断
         cli 

         mov eax,cr0 
         or eax,1 
         ; 开启保护模式
         mov cr0,eax 
         ; 需要用一个跳转指定完成实模式到保护模式的切换
         jmp dword 0x0010:flush 
                                             
         [bits 32]                          
  flush:  
         ; 0x00 0b0001 1000
         ; 段选择子是3                                   
         mov eax,0x0018                      
         mov ds,eax
      
         mov eax,0x0008   
         ; 段选择子是1                  
         mov es,eax
         ; fs新的段寄存器
         mov fs,eax
         ; gs新的段寄存器
         mov gs,eax
         ; 段选择子是4
         mov eax,0x0020     
         ; 设置栈段               
         mov ss,eax
         ; 设置栈顶指向
         ;xor esp,esp                        
         mov esp, 0xFFFFFFFF
         ; 设置显存
         mov dword [es:0x0b8000],0x072e0750 
         ; 设置显存
         mov dword [es:0x0b8004],0x072e074d
         ; 设置显存 
         mov dword [es:0x0b8008],0x07200720
         ; 设置显存 
         mov dword [es:0x0b800c],0x076b076f 

         ; 
         ; 字符串尺寸-1
         mov ecx,pgdt-string-1             
  @@1:
         ; 双重循环,内部循环执行当前位置到后续位置冒泡
         ; 对字符串执行冒泡排序
         ; 入栈
         push ecx    
         ; 设置bx为0                      
         xor bx,bx                          
  @@2:              
         ;   取得2字节                       
         mov ax,[string+bx]
         ; 低字节,高字节比较 
         cmp ah,al           
         ; 高字节>=低字节               
         jge @@3 
         ; 本来高字节<低字节,
         ; 交换后,高字节>低字节
         xchg al,ah 
         ; 将2字节从寄存器拷贝到物理内存
         mov [string+bx],ax 
  @@3:
         ; 增加bx,使得其指向下一个字符位置
         inc bx 
         ; 循环指定次数
         loop @@2 

         ; 恢复ecx
         pop ecx 
         loop @@1
         
         
         
         ; 恢复ecx
         mov ecx,pgdt-string
         ; 清空ebx
         xor ebx,ebx                        
  @@4:                                     
         mov ah,0x07
         mov al,[string+ebx]
         ; 从第二行显示排序后字符串
         mov [es:0xb80a0+ebx*2],ax         
         inc ebx
         loop @@4
         hlt 

     string           db 's0ke4or92xap3fv8giuzjcy5l1m7hd6bnqtw.'
     pgdt             dw 0
                      dd 0x00007e00      
     times 510-($-$$) db 0
                      db 0x55,0xaa

猜你喜欢

转载自blog.csdn.net/x13262608581/article/details/125704110
今日推荐