数据段描述符和代码段描述符(二)——《x86汇编语言:从实模式到保护模式》读书笔记11

这篇博文,我们编写一个C语言的小程序,来解析数据段或者代码段描述符的各个字段。这样我们阅读原书的代码就会方便一点,只要运行这个小程序,就可以明白程序中定义的数据段或者代码段的描述符了。眨眼

这段代码,我用了“位字段”的知识,这还是第一次使用C语言的这个特性呢,如果有不对的地方,欢迎博友斧正。

写代码之前,我们再复习一下数据段描述符和代码段描述符的格式。(图片选自赵炯老师的《Linux内核完全剖析》)


 

#include <stdio.h>

//定义描述符中的低32位
struct seg_des_low_word
{
    unsigned int limit_0_15:16;
    unsigned int base_0_15 :16;
    
};
//定义描述符中的高32位
struct seg_des_high_word
{
    unsigned int base_16_23 :8;
    unsigned int type       :4;
    unsigned int s          :1;
    unsigned int dpl        :2;
    unsigned int p          :1;
    unsigned int limit_16_19:4;
    unsigned int avl        :1;
    unsigned int l          :1;
    unsigned int d_b        :1;
    unsigned int g          :1;
    unsigned int base_24_31 :8;
};

//对TYPE字段进行解析
void parse_type(unsigned int t)
{
    if(t<=7)
        printf("数据段: ");
    else
        printf("代码段: ");
    switch(t)
    {
        case 0:
        case 1:
            printf("只读\n");
            break;
        case 2:
        case 3:
            printf("可读可写\n");
            break;
        case 4:
        case 5:
            printf("向下扩展,只读\n");
            break;
        case 6:
        case 7:
            printf("向下扩展,可读可写\n");
            break;
        case 8:
        case 9:
            printf("仅执行\n");
            break;
        case 10:
        case 11:
            printf("可读,可执行\n");
            break;
        case 12:
        case 13:
            printf("一致性段,仅执行\n");
            break;
        case 14:
        case 15:
            printf("一致性段,可读,可执行\n");
            break;
        default:
            break;

    }

}

void parse_seg_des(struct seg_des_low_word* pl, struct seg_des_high_word* ph)
{
    unsigned int seg_base;
    //拼接基地址字段
    seg_base = (ph->base_24_31<<24)|(ph->base_16_23<<16)|pl->base_0_15;
    printf("seg_base = %#X\n",seg_base);
    
    unsigned int seg_limit;
    //拼接段限长字段
    seg_limit = (ph->limit_16_19<<16)|pl->limit_0_15;
    printf("seg_limit = %#X\n",seg_limit);
    
    //下面的字段输出是不是很方便?这就是位字段的好处之一
    printf("S = %d\n",ph->s);
    printf("DPL = %d\n",ph->dpl);
    printf("G = %d\n",ph->g);
    printf("D/B = %d\n",ph->d_b);
    printf("TYPE = %d\n",ph->type);
    //解析TYPE(目前只支持数据段描述符和代码段描述符,其他类型的,可以自己扩充)    
    parse_type(ph->type);
}



int main(void)
{
    printf("please input the segment descriptor, low= high=\n");
    struct seg_des_high_word *high;
    struct seg_des_low_word *low;
    
    unsigned int l_word = 0;
    unsigned int h_word = 0;

    //请求用户输入描述符,先是低32位,再是高32位
    scanf("%x" "%x",&l_word,&h_word);
    printf("-----------------------\n");
    high =(struct seg_des_high_word*)&h_word;
    low =(struct seg_des_low_word*)&l_word;

    parse_seg_des(low,high);
    printf("------------------------\n");
    
    return 0;
}


好了,代码就是这样。下面看看结果吧。编译后并运行。提示我们输入:



我们就输入原书的配书代码c11_mbr.asm中

  ;创建#1描述符,保护模式下的代码段描述符
         mov dword [bx+0x08],0x7c0001ff     
         mov dword [bx+0x0c],0x00409800     
注意,输入格式是16进制(不需要前导的0x),先输入低32位,也就是7c0001ff,然后空格,再输入高32位,也就是00409800,最后回车,就出结果了。


效果还不错吧。哈哈。


(完)



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目录 第一篇 x86 基础 第1 章数与数据类型2 1.1 数 2 1.1.1 数字 2 1.1.2 进制数 3 1.1.3 进制数的排列 3 1.1.4 十六进制数 5 1.1.5 八进制数与十进制数 5 1.2 数据类型 6 1.2.1 integer 数 6 1.2.2 floating-point 数. 9 1.2.3 real number(数)与NaN(not a number) . 11 1.2.4 unsupported 编码值 14 1.2.5 浮点数精度的转换 15 1.2.6 浮点数的溢出 17 1.2.7 BCD 码 20 1.2.8 SIMD 数据 21 第2 章 x86/x64 编程基础 23 2.1 选择编译器 23 2.2 机器语言 24 2.3 Hello world 25 2.3.1 使用寄存器传递参数 26 2.3.2 调用过程 27 2.3.3 定义变量 27 2.4 16 编程、32 编程,以及64 编程 28 2.4.1 通用寄存器 28 2.4.2 操作数大小 30 2.4.2 64 模式下的内存地址 30 2.4.4 内存寻址模式 31 2.4.5 内存寻址范围 34 2.4.6 使用的指令限制 34 2.5 编程基础 34 2.5.1 操作数寻址 35 2.5.2 传送数据指令 39 2.5.3 操作指令 45 2.5.4 算术指令 47 2.5.5 CALL 与RET 指令 48 2.5.6 跳转指令 48 2.6 编辑与编译、运行 48 第 3 章编写本书的验例子 50 3.1 验的运行环境 50 3.2 生成空白的映像文件 52 3.2.1 使用nasm 编译器生成 52 3.2.2 使用bximage 工具 52 3.3 设置bochs 配置文件. 53 3.4 源代码的基本结构 54 3.5 编译源代码55 3.6 映像文件内的组织 55 3.7 使用merge 工具 56 3.7.1 merge 的配置文件 57 3.7.2 执行merge 命令 57 3.8 使用U 盘启动真机器 58 3.8.1 使用merge 工具写U 盘 58 3.8.2 使用hex 编辑软件写U 盘 59 3.9 编写boot 代码 60 3.9.1 LBA 转换为CHS 62 3.9.2 测试是否支持int 13h 扩展功能 63 3.9.3 使用int 13h 扩展读磁盘 64 3.9.4 最后看看load_module() 64 3.10 总结 66 第4 章处理器的身份 67 4.1 测试是否支持CPUID 指令 67 4.2 CPUID 指令的术语及表达 68 4.3 基本信息与扩展信息 68 4.4 处理器的型号(family,model 与stepping) 72 4.5 最大的物理地址和线性地址 73 4.6 处理器扩展状态信息74 4.6.1 探测Processor Extended State 子叶 75 4.6.2 Processor Extended State 子叶所需内存size 76 4.6.3 Processor Extended State 的保存 77 4.6.4 Processor Extended State 的恢复 78 4.7 处理器的特性 78 4.8 处理器的Cache 与TLB 信息 80 4.9 MONITOR/MWAIT 信息 83 4.10 处理器的long mode 84 第 5 章了解 Flags 85 5.1 Eflags 中的状态标志 86 5.1.1 signed 数的运算 86 5.1.2 unsigned 数的运算 89 5.2 IOPL 标志 90 5.3 TF 标志与RF 标志 93 5.4 NT 标志 95 5.5 AC 标志 96 5.6 VM 标志 98 5.7 eflags 寄存器的其他事项 99 第 6 章处理器的控制寄存器 101 6.1 CR8 102 6.2 CR3 103 6.3 CR0 104 6.3.1 保护模式PE 104 6.3.2 x87 FPU 单元的执行环境 104 6.3.3 CR0.PG 控制 108 6.3.4 CR0.CD 与CR0.NW 控制 108 6.3.5 CR0.WP 控制 110 6.3.6 CR0.AM 控制 110 6.4 CR4 110 6.4.1 CR4.TSD 与CR4.PCE 控制 110 6.4.2 CR4.DE 与CR4.MCD 控制 111 6.4.3 CR4.OSFXSR 控制 111 6.4.4 CR4.VMXE 与CR4.SMXE 控制 111 6.4.5 CR4.PCIDE 与CR4.SMEP 控制 112 6.4.6 CR4.OSXSAVE 控制 113 6.4.7 CR4 中关于页的控制 113 6.5 EFER 扩展功能寄存器 114 第 7 章 MSR. 116 7.1 MSR 的使用 116 7.2 MTRR 117 7.2.1 Fixed-range 区域的映射 118 7.2.2 MTRR 的功能寄存器 120 7.3 MSR 中对特殊指令的支持 124 7.3.1 支持sysenter/sysexit 指令的MSR 125 7.3.2 支持syscall/sysret 指令的MSR 126 7.3.3 支持swapgs 指令的MSR 127 7.3.4 支持monitor/mwait 指令的MSR 128 7.4 提供processor feature 管理 129 7.5 其他未列出来的MSR 129 7.6 关于MSR 一些后续说明 129 第篇 处理器的工作模式 第8 章地址模式 132 8.1 真的地址 132 8.2 real mode 的编址 132 8.3 real mode 的状态 133 8.4 基址的计算 134 8.5 第1 条执行的指令 134 8.6 模式下的执行环境 135 8.7 模式下的IVT 135 8.8 突破64K 限 136 8.9 A20 地址线 137 第 9 章 SMM系统管理模式探索 138 9.1 进入SMM 138 9.2 SMM 的运行环境 141 9.2.1 SMRAM 区域 141 9.2.2 SMM 执行环境的初始化 143 9.2.3 SMM 下的operand 与address 144 9.2.4 SMM 下的CS 与EIP 144 9.2.5 SMM 下的SS 与ESP 145 9.3 SMM 里的中断 145 9.4 SMI 的Back-to-Back 响应 147 9.5 SMM 里开启保护模式 147 9.6 SMM 的版本 148 9.7 I/O 指令的重启及Halt 重启 151 9.8 SMM 的退出 152 9.9 SMBASE 的重定. 153 9.10 SMI 处理程序的初始化 154 9.11 SMM 的安全 156 9.11.1 芯片组的控制 156 9.11.2 处理器对SMRAM 空间的限制 158 9.11.3 cache 的限制 160 9.12 测试SMI 处理程序 161 第 10 章 x86/x64 保护模式体系(上) 163 10.1 x86/x64 的权限 164 10.2 保护模式下的环境 164 10.2.1 式管理所使用的资源 165 10.2.2 paging 分页机制所使用的资源 165 10.3 物理地址的产生 166 10.4 式管理机制 167 10.4.1 式内存管理 168 10.4.2 式的保护措施 168 10.5 式管理的数据结构 169 10.5.1 Segment Selector(选择子) 169 10.5.2 Descriptor Table(描述符表) 172 10.5.3 Segment Selector Register(寄存器) 174 10.5.4 Segment Descriptor(描述符) 175 10.5.5 LDT 描述符与LDT 258 10.6 开启保护模式 259 10.6.1 初始化GDT 260 10.6.2 初始化IDT. 262 10.6.3 切换到保护模式 263 第11x86/x64 保护模式体系(下) 265 11.1 物理页面 265 11.1.1 处理器的最高物理地址(MAXPHYADDR) 266 11.1.2 物理页面的大小 267 11.1.3 页转换模式(Paging Mode) 268 11.2 paging 机制下使用的资源 270 11.2.1 寄存器 270 11.2.2 CPUID 查询leaf 270 11.2.3 寄存器的控制 271 11.2.4 页转换表资源 272 11.3 32 paging 模式(non-PAE 模式) 273 11.3.1 CR3 结构 274 11.3.2 32 paging 模式下的PDE 结构 275 11.3.3 使用32 paging 279 11.4 PAE paging 模式. 282 11.4.1 在Intel64 下的CR3 与PDPTE 寄存器 283 11.4.2 在AMD64 下的CR3 285 11.4.3 PAE paging 模式里的PDPTE 结构 286 11.4.4 PAE paging 模式里的PDE 结构 286 11.4.5 PAE paging 模式里的PTE 结构 288 11.4.6 使用和测试PAE paging 模式 288 11.4.7 使用和测试Execution Disable 功能 292 11.5 IA-32e pagi
### 回答1: 这视频介绍了x86汇编语言下,如何从实模式切换到保护模式。 首先,视频介绍了模式的特点和局限性。模式下,CPU只能寻址1MB的内存空间,同时所有的程序都需要运行在同一个特权级下,对于大型程序和操作系统而言非常不利。 接着,视频介绍了如何切换到保护模式保护模式下,CPU可以通过基地址和选择器来访问4GB的内存空间,同时程序可以运行在不同的特权级下。切换到保护模式的关键步骤包括:设置GDT和IDT表、开启A20线、设置CR0寄存器、跳转到保护模式代码等。 最后,视频演示了如何编写汇编代码保护模式的切换。代码包括定义GDT和IDT表、开启A20线的函数、设置CR0寄存器的函数,以及跳转到保护模式代码的函数。通过这视频的学习,我们了解了从实模式保护模式的切换原理和现方法,对于深入理解操作系统和底层编程有着重要的意义。 ### 回答2: x86汇编语言是计算机的底层语言,包括模式保护模式两种运行模式模式是早期计算机的一种运行模式,它的内存访问方式简单,容易理解。在模式下,整个物理内存空间可以直接寻址,但同时也带来一些安全问题。为了保护内存和提高计算机运行的稳定性,最终出现了保护模式保护模式x86汇编语言的一种运行模式,它可以让计算机利用内存管理单元(MMU)来对内存进行隔离和保护。在保护模式下,内存空间被分为多个,并为每个赋予相应的权限和特权级别。这样可以有效保护计算机的内存空间,避免程序之间相互侵入和破坏。 保护模式的运行需要经过一系列的初始化,包括:打开地址线扩展、禁用中断、打开分页等操作。这些操作可以通过设置控制寄存器和描述符表来现。 在保护模式下,程序运行的特权级别由RPL(Requested Privilege Level)和CPL(Current Privilege Level)两个标志来控制。CPL代码数据的选择子中,代表当前运行程序的权限级别,而RPL代码选择子和数据选择子中,用来判断程序是否有权访问对应的。 在保护模式下,虚拟地址需要经过地址转换才能转换成物理地址,这需要使用页表来对虚拟地址进行映射。页表和页目录存储在内存中,需要通过控制寄存器来取出相应的值进行地址转换。 总之,x86汇编语言模式保护模式都有各自的特点和应用场合,学习x86汇编语言需要深入理解这两种运行模式的原理和现过程。 ### 回答3: x86汇编语言是计算机硬件操作指令的编程语言,是本质上依赖于CPU架构和指令集的语言。根据其中对内存的处理方式的不同,x86汇编语言可以分为模式保护模式模式是指CPU直接访问物理内存,地址总线是20,内存寻址空间最大为1MB。模式下的程序可以访问系统资源,例如中断处理、内存读写等操作。但模式下内存空间过小,程序出错容易导致系统崩溃。 保护模式是一种更加灵活和安全的工作状态,地址总线扩展到了32,理论内存访问空间可以达到4GB以上。保护模式下内存被划分为多个,程序可以在相互独立的之间进行操作,可以在级别上分配权限,从而提高代码的安全性。同时,保护模式也支持虚存技术,通过硬件的支持,可以将程序的际运行数据放入物理内存和虚拟内存的组合体内,从而可以利用硬盘来进行虚拟内存的支持,使得多个程序在同一系统上运行时不会相互干扰,同时提高系统的稳定性。 因此,在现代操作系统上,保护模式是必需的。x86汇编语言需要不同的功能选项来在模式保护模式之间进行转换。在视频中,我们可以学习如何从实模式切换到保护模式,并掌握如何在保护模式下使用不同的功能选项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值