i386 寄存器整理

i386的寄存器

   80386作为80X86系列中的一员,必须保证向后兼容,也就是说,既要支持16位的处理器,也要支持32位的处理器。在8086中,所有的寄存器都是16位的,下面我们来看一下80386中寄存器有何变化:

·      把16位的通用寄存器、标志寄存器以及指令指针寄存器扩充为32位的寄存器

·      段寄存器仍然为16位。

·      增加4个32位的控制寄存器

·      增加4个系统地址寄存器

·      增加8个调式寄存器

·      增加2个测试寄存器

1  通用寄存器

8个通用寄存器是8086寄存器的超集,它们的名称和用途分别为:

EAX  一般用作累加器

EBX  一般用作基址寄存器(Base)

ECX  一般用来计数(Count)

EDX  一般用来存放数据(Data)

ESP  一般用作堆栈指针(Stack Pointer)

EBP  一般用作基址指针(Base Pointer)

ESI   一般用作源变址(Source Index)

EDI   一般用作目标变址(Destinatin Index)

      8个通用寄存器中通常保存32位数据,但为了进行16位的操作并与16为机保持兼容,它们的低位部分被当成8个16位的寄存器,即AX、BX…DI。为了支持8位的操作,还进一步把EAX、EBX、ECX、EDX这四个寄存器低位部分的16位,再分为8位一组的高位字节和低位字节两部分,作为8个8位寄存器。这8个寄存器分别被命名为AH、BH、CH、DH和AL、BL、CL、DL。对8位或16位寄存器的操作只影响相应的寄存器。例如,在做8位加法运算时,位7的进位并不传给目的寄存器的位9,而是把标志寄存器中的进位标志(CF)置位。因此,这8个通用寄存器既可以支持1位、8位、16位和32位数据运算,也支持16位和32位存储器寻址。

2  段寄存器

8086中有4个16位的段寄存器:CS、DS、SS、ES,分别用于存放可执行代码的代码段、数据段、堆栈段和其他段的基地址。在80386中,有6个16位的段寄存器,但是,这些段寄存器中存放的不再是某个段的基地址,而是某个段的选择符(Selector)。因为16位的寄存器无法存放32位的段基地址,段基地址只好存放在一个叫做描述符表(Descriptor)的表中。因此,在80386中,我们把段寄存器叫做选择符。下面给出6个段寄存器的名称和用途:

CS 代码段寄存器

DS 数据段寄存器

SS 堆栈段寄存器

ES、FS及GS 附加数据段寄存器

有关段选择符、描述符表及系统表地址寄存器将在段机制一节进行详细描述。

3  状态和控制寄存器
状态和控制寄存器是由标志寄存器EFLAGS、指令指针EIP和4个控制寄存器组成,如图2.1所示:

图2.1状态和控制寄存器
标志寄存器EFLAGS
指令指针EIP
机器状态字CR0
Intel保留CR1
页故障地址CR2
页目录地址CR3

指令指针寄存器和标志寄存器

指令指针寄存器EIP中存放下一条将要执行指令的偏移量(offset ),这个偏移量是相对于目前正在运行的代码段寄存器CS而言的。偏移量加上当前代码段的基地址,就形成了下一条指令的地址。EIP中的低16位可以分开来进行访问,给它起名叫指令指针IP寄存器,用于16位寻址。

标志寄存器EFLAGS存放有关处理器的控制标志,如图2.2所示。标志寄存器中的第1、3、5、15位及18~31位都没有定义。


    在这些标志位中,我们只介绍在Linux内核代码中常用且重要的几个标志位:

第8位TF(Trap Flag)是自陷标志,当将其置1时则可以进行单步执行。当指令执行完后,就可能产生异常1的自陷(参看第四章)。也就是说,在程序的执行过程中,每执行完一条指令,都要由异常1处理程序 (在Linux内核中叫做debug())进行检验。当将第8位清0后,且将断点地址装入调试寄存器DR0~DR3时,才会产生异常1的自陷。                                 

第12、13位IOPL是输入输出特权级位,这是保护模式下要使用的两个标志位。由于输入输出特权级标志共两位,它的取值范围只可能是0、1、2和3共4个值,恰好与输入输出特权级0~3级相对应。但Linux内核只使用了两个级别,即0和3级,0表示内核级,3表示用户级。在当前任务的特权级CPL(Current Privilege Level)高于或等于输入输出特权级时,就可以执行像IN、OUT、INS、OUTS、STI、CLI和LOCK等指令而不会产生异常13(即保护异常)。在当前任务特权级CPL为0时,POPF(从栈中弹出至标志位)指令和中断返回指令IRET可以改变IOPL字段的值。

第9位IF(Interrupt Flag)是中断标志位,是用来表示允许或者禁止外部中断(参看第四章)。若第9位IF被置为1,则允许CPU接收外部中断请求信号;若将IF位清0,则表示禁止外部中断。在保护模式下,只有当第12、13位指出当前CPL为最高特权级时,才允许将新值置入标志寄存器EFLAGS以改变IF位的值。

第10位DF(Direction Flag)是定向标志。DF位规定了在执行串操作的过程中,对源变址寄存器ESI或目标变址寄存器EDI是增值还是减值。如果DF为1,则寄存器减值;若DF为0,则寄存器值增加。

第14位NT是嵌套任务标志位。在保护模式下常使用这个标志。当80386在发生中断和执行CALL指令时就有可能引起任务切换。若是由于中断或由于执行CALL指令而出现了任务切换,则将NT置为1。若没有任务切换,则将NT位清0。

第17位VM (Virtual 8086 Mode Flag)是虚拟8086方式标志,是80386新设置的一个标志位。表示80386CPU是在虚拟8086环境中运行。如果80386CPU是在保护模式下运行,而VM为又被置成1,这时80386就转换成虚拟8086操作方式,使全部段操作就像是在8086CPU上运行一样。VM位只能由两种方式中的一种方式给予设置,即或者是在保护模式下,由最高特权级(0)级代码段的中断返回指令IRET设置,或者是由任务转换进行设置。Linux内核实现了虚拟8086方式,但在本书中我们不准备对此进行详细讨论。

   从上面的介绍可以看出,要正确理解标志寄存器EFLAGS的各个标志需要很多相关的知识,有些内容在本章的后续部分还会涉及到。在后面的章节中,你会体会如何灵活应用这些标志。

控制寄存器

状态和控制寄存器组除了EFLAGS、EIP ,还有四个32位的控制寄存器,它们是CR0,CR1,CR2和CR3。现在我们详细看看它们的结构,如图 2-3所示。

图 2-3 386中的控制寄存器组

图 2-4 PG位和PE位定义的操作方式

CR1是未定义的控制寄存器,供将来的处理器使用。

CR2是页故障线性地址寄存器,保存最后一次出现页故障的全32位线性地址。

CR3是页目录基址寄存器,保存页目录表的物理地址,页目录表总是放在以4K字节为单位的存储器边界上,因此,它的地址的低12位总为0,不起作用,即使写上内容,也不会被理会。

这几个寄存器是与分页机制密切相关的,因此,在进程管理及虚拟内存管理中会涉及到这几个寄存器,读者要记住CR0、CR2及CR3这三个寄存器的内容。

4   系统地址寄存器

  80386有4个系统地址寄存器,如图2.5所示,它保存操作系统要保护的信息和地址转换表信息:

这4个专用寄存器用于引用在保护模式下所需要的表和段,它们的名称和作用如下:

5 调试寄存器和测试寄存器

调试寄存器

80386为调试提供了硬件支撑。在80386芯片内有8个32位的调试寄存器DR0~DR7,如图2.6所示。

这些寄存器可以使系统程序设计人员定义4个断点,用它们可以规定指令执行和数据读写的任何组合。DR0~DR3是线性断点地址寄存器,其中保存着4个断点地址。DR5、DR6是两个备用的调试寄存器,目前尚未定义。DR6是断点状态寄存器,其低序位是指示符位,当允许故障调试并检查出故障而进入异常调试处理程序(debug())时,由硬件把指示符位置1,调试异常处理程序在退出之前必须把这几位清0。DR7是断点控制寄存器,它的高序半个字又被分为4个字段,用来规定断点字段的长度是1个字节、2个字节、4个字节及规定将引起断点的访问类型。低序半个字的位字段用于“允许”断点和“允许”所选择的调试条件。

测试寄存器

80386有两个32位的测试寄存器TR6和TR7。这两个寄存器用于在转换旁视缓冲器(Translation Lookaside Buffer)中测试随机存储器(RAM)和相联存储器(CAM)。TR6是测试命令寄存器,其内存放测试控制命令。TR7是数据寄存器,其内保存转换旁路缓冲器测试的数据。

· 全局描述符表寄存器GDTR(Global Descriptor Table Register ),是48位寄存器,用来保存全局描述符表(GDT)的32位基地址和16为GDT的界限。

· 中断描述符表寄存器IDTR(Interrupt Descriptor Table Register),是48位寄存器,用来保存中断描述符表(IDT)的32位基地址和16为IDT的界限。

· 局部描述符表寄存器LDTR(Global Descriptor Table Register ),是16位寄存器,保存局部描述符表LDT段的选择符。

· 任务状态寄存器TR(Task State Register)是16位寄存器,用于保存任务状态段TSS段的16位选择符。

用以上4个寄存器给目前正在执行的任务(或进程)定义任务环境、地址空间和中断向量空间。有关全局描述符表GST、中断描述符表IDT、局部描述符表LDT及任务状态段TSS的具体内容将在稍后进行详细描述。

这几个寄存器中保存全局性和任务无关的机器状态。

CR0中包含了6个预定义标志,0位是保护允许位PE(Protedted Enable),用于启动保护模式,如果PE位置1,则保护模式启动,如果PE=0,则在实模式下运行。1位是监控协处理位MP(Moniter coprocessor),它与第3位一起决定:当TS=1时操作码WAIT是否产生一个“协处理器不能使用”的出错信号。第3位是任务转换位(Task Switch),当一个任务转换完成之后,自动将它置1。随着TS=1,就不能使用协处理器。CR0的第2位是模拟协处理器位 EM (Emulate coprocessor),如果EM=1,则不能使用协处理器,如果EM=0,则允许使用协处理器。第4位是微处理器的扩展类型位ET(Processor Extension Type),其内保存着处理器扩展类型的信息,如果ET=0,则标识系统使用的是287协处理器,如果 ET=1,则表示系统使用的是387浮点协处理器。CR0的第31位是分页允许位(Paging Enable),它表示芯片上的分页部件是否允许工作,下一节就会讲到。由PG位和PE位定义的操作方式如图2.4 所示。

<think>好的,用户想了解汇编语言教程,我需要整理一个结构清晰的中文回答。首先,我得确定用户的需求是什么。可能是想学习汇编语言的基础,或者是想了解如何开始学习。用户可能没有编程经验,或者有其他语言的基础,但不确定。所以需要从基础开始,逐步深入。 首先,汇编语言的定义和作用。需要简单明了,说明它和机器语言的关系,以及为什么重要。然后,可能的应用场景,比如嵌入式系统、逆向工程等,让用户知道学习它的用途。 接下来,基本概念部分。寄存器、指令集、内存地址、汇编指令格式这些是关键点。每个部分需要简要解释,例子要简单,比如用MOV指令说明数据传输。要注意使用行内公式,比如寄存器用$eax$,内存地址用$[0x00400000]$,符合用户的格式要求。 然后是开发环境搭建。不同的平台有不同的工具,比如NASM、GCC、MASM。需要列出常用工具,并给出编译链接的示例命令。这部分要具体,但避免太复杂,用户可能需要步骤指导。 编写第一个程序部分,应该以经典的“Hello World”为例。给出示例代码,并解释每一行的大致作用,比如系统调用号、寄存器参数。注意代码注释用中文,帮助理解。 学习路径建议分阶段,从基础到高级。每个阶段列出关键点,比如先学寄存器和指令,再学控制结构和内存管理,最后到优化和实际项目。这样用户可以循序渐进。 最后推荐资源,书籍和在线教程,选择经典的中文资源,方便用户查找。同时提醒坚持和实践的重要性,鼓励用户动手操作。 需要检查是否所有数学表达式和代码都用对了格式,比如寄存器用$包裹,独立公式用$$。但在这个回答里可能数学公式不多,主要是代码和术语。确保没有使用Markdown,段落清晰,用序号和标题分隔。 可能用户是计算机专业学生或爱好者,想深入了解底层编程。要避免过于晦涩,保持解释的易懂性。同时,提醒学习汇编的挑战,需要耐心和实践,这样用户有心理准备。 总结下来,结构分为概述、基本概念、环境搭建、第一个程序、学习路径、资源推荐和总结。每个部分简明扼要,重点突出,符合用户的需求。</think>以下是一份结构清晰的汇编语言学习指南: 一、汇编语言概述 $$汇编语言 = 机器指令的助记符 + 控制硬件的低级语言$$ • 直接操作CPU寄存器/内存 • 与硬件架构强相关(x86/ARM/MIPS等) • 执行效率高但可读性较低 二、核心概念解析 1. 寄存器 - 通用寄存器:$eax$, $ebx$, $ecx$, $edx$(32位) - 专用寄存器:$eip$(指令指针), $esp$(栈指针) 2. 指令格式 $$操作码\ 操作数1,\ 操作数2$$ 例:$mov\ eax,\ 10$ # 将立即数10存入eax 3. 内存访问 使用方括号表示内存地址: $mov\ [0x00400000],\ ecx$ # 将ecx值存入指定地址 三、开发环境搭建 1. 工具链: - 汇编器:NASM(跨平台)/MASM(Windows) - 链接器:LD(GCC)/LINK(Visual Studio) - 调试器:GDB/WinDbg 2. 编译流程示例: ```bash nasm -f elf hello.asm # 生成目标文件 ld -m elf_i386 -o hello hello.o # 生成可执行文件 ``` 四、第一个汇编程序(以x86 Linux为例) ```assembly section .data msg db 'Hello World!', 0xA ; 定义字符串 len equ $ - msg ; 计算长度 section .text global _start _start: ; 系统调用 write(1, msg, len) mov eax, 4 ; 系统调用号 mov ebx, 1 ; 文件描述符(stdout) mov ecx, msg ; 字符串地址 mov edx, len ; 字符串长度 int 0x80 ; 触发中断 ; 退出程序 exit(0) mov eax, 1 ; 系统调用号 mov ebx, 0 ; 返回码 int 0x80 ``` 五、学习路径建议 1. 初级阶段 - 掌握寄存器与内存操作 - 学习常用指令:MOV/ADD/SUB/CMP/JMP - 理解栈操作机制 2. 中级阶段 - 掌握过程调用规范 - 学习中断处理 - 理解内存分段机制 3. 高级阶段 - 指令级优化技巧 - SIMD指令集(如SSE/AVX) - 与C语言混合编程 六、推荐学习资源 1. 经典教材: - 《汇编语言(第4版)》王爽 著(中文入门经典) - 《x86汇编语言:从实模式到保护模式》李忠 著 2. 在线教程: - 麻省理工学院《计算机组成与系统设计》公开课 - OSDev Wiki(操作系统开发维基) 七、重要提示 学习汇编语言需要: 1. 熟悉二进制/十六进制数制 2. 理解计算机组成原理 3. 配合调试器实践观察寄存器变化 4. 从简单程序开始逐步深入 建议学习周期:每天2小时,持续2-3个月可掌握基础,配合实际项目(如简单操作系统开发)能显著提升理解深度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值