如何制作产品网站模板下载地址国外一个专门做配乐的网站
- 作者: 五速梦信息网
- 时间: 2026年03月21日 09:49
当前位置: 首页 > news >正文
如何制作产品网站模板下载地址,国外一个专门做配乐的网站,保定建设银行网站首页,ae在线生成视频目录 引用与说明 3.1、地址、section、vstart 浅尝辄止 1、什么是地址 2、什么是 section【汇编】 3、什么是 vstart【汇编】 3.2、CPU 的实模式 1、CPU 工作原理【重要】 2、实模式下的寄存器 4、实模式下 CPU 内存寻址方式 5、栈到底是什么玩意儿 6 ~ 8 无条件转移… 目录 引用与说明 3.1、地址、section、vstart 浅尝辄止 1、什么是地址 2、什么是 section【汇编】 3、什么是 vstart【汇编】 3.2、CPU 的实模式 1、CPU 工作原理【重要】 2、实模式下的寄存器 4、实模式下 CPU 内存寻址方式 5、栈到底是什么玩意儿 6 ~ 8 无条件转移【汇编】 6、实模式下的 ret 7、实模式下的 call 8、实模式下的 jmp 9、标志寄存器 flags 10、有条件转移 其他问题 引用与说明 《操作系统真相还原》作者郑钢原书讲解得非常详细但是战线拉得太长反而容易找不到重点。所以编写本篇文章旨在让读者抓住重点也可以作为原章节的导读。3.1 和 3.2 节在讲一些概念和汇编操作如果读者对这些概念比较熟悉完全可以跳过本篇并不影响实操。从 3.3 节开始进行实际操作将在下一篇讲解。 建议略读章节3.3.3、实模式下内存分段由来 3.1、地址、section、vstart 浅尝辄止 1、什么是地址 地址只是数字描述各种符号在源程序中的位置是各符号相对于文件开头的偏移量。编译器给各符号分配地址这些符号在空间上彼此相邻连续分布。 地址等于上一个地址 上一个地址处的内容的长度。例如地址列第二行的 3 等于 “上一个地址 0” “上一个地址 0 处的内容B80000 的长度 3”。“B80000” 是一个 6 位的十六进制数。每两个十六进制数字对应一个字节“B8” 是第一个字节“00” 是第二个字节“00” 是第三个字节。“B80000” 的长度是 3 个字节。“长度是 3”这个描述它通常指的是这个十六进制数在内存中占用的字节数。 2、什么是 section【汇编】 section 称为节功能是在程序中宣称一个区域为了让程序员在逻辑上将程序划分成几个部分。 关键字 section 没有对程序中的地址产生任何影响section 中的数据的地址依然是相对于整个文件的顺延仅仅是在逻辑上让开发人员梳理程序之用。 3、什么是 vstart【汇编】 vstart 是虚拟起始地址section 用 vstart 来修饰后被赋予一个虚拟起始地址它被用来计算在该 section 内的所有引用地址。虚拟起始地址 ! x86 CPU 开启分页后的虚拟地址。 vstart 按照开发人员的意愿安排新的起始地址不再以文件开头 0 为起始其地址若超过文件大小则不会落在文件内也就是说根据此地址在文件中是找不到相关数据的文件中的所有符号都不在这个地址上所以是虚拟的。 用 vstart 的时机是预先知道我的程序将来被加载到某地址处。第二章代码中 mbr 用 vstart 0x7c00 来修饰是开发人员知道 mbr 要被加载器BIOS加载到物理地址 0x7c00mbr 中后续的物理地址都是 0x7c00 。 3.2、CPU 的实模式 实模式是指 8086 CPU 的寻址方式、寄存器大小、指令用法等是用来反应 CPU 在该环境下如何工作的概念并不是单指某一方面的设置。CPU 的唯一任务就是执行指令。 1、CPU 工作原理【重要】 程序被加载到内存后指令这时都在内存中了。控制单元要取下一条待运行的指令该指令的地址在程序计数器 PC 中在 x86 CPU 上程序计数器就是 csip。控制单元从 cs 寄存器中读取段基址从 ip 寄存器读取偏移量。读取 ip 寄存器后将此地址送上地址总线CPU 根据此地址便得到了指令并将其存入到指令寄存器 IR 中。 指令译码器根据指令格式检查指令寄存器中的指令先确定操作码是什么再检查操作数类型若是在内存中就将相应操作数从内存中取回放入自己的存储单元若操作数是在寄存器中就直接用免了取操作数这一过程。 操作码有了操作数也齐了操作控制器给运算单元下令开工于是运算单元便真正开始执行指令了。运算单元执行指令并将结果存放在指定的寄存器或内存。 在执行当前指令的同时在不跨段的情况下CPU 以 ”当前 IP 寄存器中的值 当前执行指令的机器码长度“ 的和作为新的代码段内偏移地址将其存入 IP 寄存器。如果下一条指令需要跨段访问还要加载新的段基址到 CS 寄存器。这样便得到了下一条指令的地址。接着控制单元又要取下一条指令了流程回到了本阶段开头。 2、实模式下的寄存器 寄存器是使用触发器实现的工作速度极快。 CPU 中的寄存器分类对程序员不可见的寄存器无法直接使用但部分可以被程序员初始化全局描述符表寄存器 GDTR中断描述符表寄存器 IDTR局部描述符表寄存器 LDTR任务寄存器 TR控制寄存器 CR0~3指令指针寄存器 IP标志寄存器 flags调试寄存器 DR0~7对程序员可见的寄存器进行汇编语言设计时能直接操作的就是这些寄存器段寄存器见书【P74、P75】这里不用太纠结讲到寻址方式时就知道运用在哪了通用寄存器非常详细需要仔细阅读见书【P75、P76】 【注】图 3-3 和 表 3-2 中的各个寄存器的名字要留个印象接下来讲内存寻址时各个寄存器会频繁出现 讲到哪个寄存器时请一定回来查找这几张图和表。 4、实模式下 CPU 内存寻址方式 寻址指的是 CPU 在寻找 “数” 的地址找到 “数” 的所在地从哪来往哪去。这个 “数” 可以是源操作数也可以是目的操作数。Intel 汇编语言语法是 “指令目的操作数源操作数”。 每一种寻址方式对应一种电路实现增加一种寻址方式会增加硬件电路的复杂性所以寻址方式是有限的。 寄存器寻址 寄存器寻址是最直接的寻址方式它是指 “数” 在寄存器中直接从寄存器中拿数据就行了。 ; 用 mul 指令实现 0x10 * 0x9 mov ax, 0x10 ; 第一条命令是将 0x10 存入 ax 寄存器 mov dx, 0x9 ; 第二条命令是将 0x9 存入 dx mul dx ; 第三条指令是求 ax 和 dx 的乘积乘积的高16位在 dx 寄存器低16位在 ax 寄存器 以上三条指令都是寄存器寻址。只要牵扯到寄存器的操作无论其是源操作数还是目的操作数都是寄存器寻址。上面的第一、二条指令它们的源操作数都是立即数所以也属于立即数寻址。 立即数寻址 立即数就是常数。指令由操作码和操作数组成得到一个数往往不容易。这个数要么在寄存器中要么在内存中都是间接给出的所以得到数就要花费一些 CPU 周期。如果操作数 直接 存在指令中直接拿过来立即就能用了。为了突显 立即就能用 的高效率此数便称为立即数。立即数免去了找数的过程。 mov ax, 0x18 ; 立即数寻址 mov ds, ax ; 寄存器寻址 mov ax, macro_selector ; 立即数寻址 mov ax, label_start ; 立即数寻址 第一条指令中的源操作数 0x18 是立即数目的操作数 ax 是寄存器所以它既是立即数寻址也是寄存器寻址。第二条指令中源操作数和目的操作数都是寄存器所以纯粹是寄存器寻址。第三条指令的源操作数 macro_selector 是个宏第四条指令的源操作数 label_start 是个标号这两个在编译阶段会转换为数字最终可执行文件中的依然是立即数。 内存寻址 以上两种寻址方式操作数一个是在寄存器中一个是在指令中直接给出。它们都不在内存中。操作数在内存中的寻址方式称为内存寻址。 由于访问内存是用 段基址段内偏移地址 的形式此形式只用在内存访问中。默认情况下数据段寄存器是 DS即段基址已经有了只要再给出段内偏移地址就可以访问内存了最终起决定作用的、有效的是段内偏移地址所以段内偏移地址称为有效地址。 “[x]” 表示取了 x 的地址其中 x 通常指的是一个寄存器或一个计算出的地址。 直接寻址属于内存寻址 直接寻址就是将直接在操作数中给出的数字作为内存地址通过中括号的形式告诉CPU取此地址中的值作为操作数。 mov ax, [0x1234] mov ax, [fs:0x5678] 0x1234 是段内偏移地址DS 是数据段寄存器的默认段寄存器【图 3-3】。这条指令是将内存地址 DS0x1234 处的值写入 ax 寄存器。段基址16 变成 20 位地址后再加上段内偏移地址 0x1234结果还是 20 位地址。 第二条指令中由于使用了段跨越前缀 fs这意味着该指令使用 FS 段寄存器而不是默认的 DS。最终的内存地址是 fs 寄存器的值16 0x5678CPU 到此内存地址取值再存入 ax 寄存器。 【注】不要和立即数寻址混了立即数寻址中的数字是直接拿来就用作操作数了直接寻址中的数字是用来进一步寻址的。 基址寻址属于内存寻址 基址寻址就是在操作数中用 bx 寄存器或 bp 寄存器作为地址的起始地址的变化以它为基础。用寄存器作为内存寻址在实模式下必须用 bx 或 bp 寄存器。保护模式下基址寄存器可选择的很多可以是全部的通用寄存器。 bx 寄存器的默认段寄存器是 DS。例如 add word[bx], 0x1234 这条指令将 0x1234 加上内存地址 ds:bx 处的值后再存入内存地址 ds:bx 中。这条指令用到了立即数寻址和内存基址寻址两种方式。 add word[bx], 0x1234 bp 寄存器的默认段寄存器是 SS即 bp 和 sp 都是栈的偏移地址即 bp 是用来访问栈的。 【Q】为什么已经有了 sp 寄存器来 专门 访问栈还要再单独准备个 bp 呢 【A】 访问栈有两种方式一种是把栈当作 “栈” 来使用也就是用 push 和 pop 指令操作栈sp 寄存器作为栈顶指针相当于栈中数据的游标这是专门给 push 指令和 pop 指令做导航用的寄存器push 指令往哪个内存压入数据pop 将哪个地址的数据弹出栈都要看 sp 的值是多少。但这样我们只能访问到栈顶即 sp 指向的地址没有办法直接访问到栈底和栈顶之间的数据。 ; 实模式下CPU 字长是16所以实模式下的 push 指令默认情况下是压入2字节的数据。执行 push ax: sub sp, 2 ; 先将 sp 的值减去 mov sp, ax ; 再将 ax 的值 mov 到新的 sp 指向的内存 ; 实模式下 pop 指令。执行 pop ax: mov ax,[sp] ; 先将 sp 指向的值 mov 到 ax add sp,2 ; 再将 sp 的指针2 很多时候我们需要读写栈中的数据即需要把栈当成普通数据段那样访问。举个需要直接写栈的例子比如标志寄存器 eflags 无法直接修改只能用 pushf 指令把 eflags 寄存器的内容压到栈中我们在栈中修改完后再用 popf 把它弹回到 eflags 中。处理器为了让开发人员方便控制栈中数据提供了这种把栈当成数据段来访问的方式可以用寄存器 bp 来给出栈中偏移量所以 bp 默认的段寄存器就是 SS这样就可以通过 SSbp 的方式把栈当成普通的数据端来访问了。 【注】 “栈中保存局部变量和函数参数” 的例子非常详细见书【P80、P81】。 变址寻址属于内存寻址 变址寻址和基址寻址类似只是寄存器由 bx、bp 换成了 si 和 di。si 是指源索引寄存器di 是指目的索引寄存器。两个寄存器的默认段寄存器也是 ds。 mov [di], ax ; 将寄存器 ax 的值存入 ds:di 指向的内存 mov [si0x1234], ax ; 变址中也可以加个偏移量 变址寻址主要是用于字符搬运方面的指令这两个寄存器在很多指令中都要成对使用如 movsbmovswmovsd 等。 基址变址寻址属于内存寻址 名字上看这是基址寻址和变址寻址的结合即基址寄存器 bx 或 bp 加一个变址寄存器 si 或 di。 了解即可项目中没用到。 mov [bxdi], ax ; 将 ax 中的值送入以 ds 为段基址bxdi 为偏移地址的内存 add [bxsi], ax ; 将 ax 与ds:bxsi处的值相加后存入内存ds: bxsi] 【汇编】mul 指令说明 mul dx这条指令将 ax 寄存器中的值与 dx 寄存器中的值相乘。mul 指令是无符号乘法指令它会用 ax 寄存器中的值作为被乘数用 dx 寄存器中的值作为乘数。乘法结果的低 16 位将存放在 ax 寄存器中。乘法结果的高16位将存放在 dx 寄存器中。 ax 寄存器的值0x10 16dx 寄存器的值0x9 9乘积 16 × 9 144十六进制表示是 0x90。ax 存放乘积的低 16 位因此 ax 寄存器中的值为 0x90 (144)。dx 存放乘积的高 16 位。由于 144 的乘积在 16 位范围内没有高位所以 dx 寄存器中的值将为 0x0 (0)。 【汇编】word 数据类型伪指令【P89】 数据类型伪指令有 byte、word、dword、qword 等它们用在操作数前相当于做数据类型强制转换。在汇编语言中无论操作数是立即数、寄存器或是内存都可以用数据类型伪指令。 在 16 位实模式下默认数据宽度是 16 位关键字 “word” 用来告诉 CPU 一次要读或写 2 字节。 mov word [addr], near_proc 例如使用 “mov word [addr], near_proc” 指令时addr 是个 4 字节的变量用来存储函数 near_proc 的地址。 near_proc 是个函数名本身是个地址在编译阶段就会被替换为数字这个数字的宽度是不定的比如 0x18 是 0x0018还是 0x00000018 呢这涉及到读写多少个字节的问题这也是高级语言中数据类型的作用。由于此时是在 16 位的实模式下我们要用 16 位的地址必须得告诉 cpu 在此内存地址处连续读 2 字节就够了所以用关键字 word。 5、栈到底是什么玩意儿 CPU 中有栈段 SS 寄存器和栈指针 SP 寄存器用来指定当前使用的物理地址。堆栈是人们常说的栈和堆没关系。 内存中的栈是物理上的把数据结构中的栈的概念用物理硬件来实现。它同数据段、代码段一样是个内存中的区域也就是栈段寄存器 SS 和栈指针 SP 所指向的内存区域。我们常听说的栈溢出指的就是这个内存区域无法容纳数据了。 栈要实现线性结构。内存就是线性结构要做的就是给栈指定一片内存区域区域的起始地址作为栈基址存入栈基址寄存器 SS 中另一端是动态变化的用栈指针寄存器 SP 来指定。栈在使用过程中是向下扩展的所以栈顶地址肯定小于栈底地址。栈中的内存地址也是用 段基址 SS 的值16栈指针 SP段内偏移地址形成的 20 位地址访问到的。 由于是硬件实现的栈故硬件提供了相应的方法来存取栈即 push 和 pop 指令。在操作 SP 时要加减字长CPU的字长指一次可处理的数据的长度。在实模式下的字长是 16所以实模式下的 push 和 pop 指令默认情况下是压入或弹出 2 字节的数据SP 加上或减去 2 字节。【注】之前在讲解基址寻址时有例子。 【注】如图 3-9 所示虽然栈是向下发展的但栈也是内存访问内存依然是从低地址往高地址假如当前栈顶是 0x1233E栈顶数据占 2 字节的话其范围是 0x1233E ~ 0x1233F。 即使是这里的硬件栈咱们也可以自己维护指针如 push ax 可以这样代替 mov bp, sp sub bp, 2 mov [bp], ax bp 默认的段寄存器就是 SS用 bp 的时候直接操作的便是栈bp 就相当于栈指针。 6 ~ 8 无条件转移【汇编】 IP 寄存器不能通过赋值更改所以 CPU 中提供了很多可以改变 CPU 执行流的指令如 call、ret、jmp 等它们在内部实现上包含了许多微操作用于设置相关数据结构但是表面上看来只是一个指令。它们在原理上是修改寄存器 CS 和 IP 的值将 CPU 导向新的位置。 “相对” 时操作数的计算无论是 call还是 jmp只要是 相对 的形式操作数都是这样来的目标地址减去当前指令地址后所得的差再减去机器码大小。 【注】这里将几个关键字给总结了一下这些关键字的组合表示了调用方式的特征在 call 和 jmp 中都是适用的。我仅在个别调用方法中给出名字的解释读者可以依葫芦画瓢分析。 【汇编】near、short、far 修饰符 near 的意思同数据类型伪指令 word 一样指在内存地址处取 2 字节内容或者将操作数强制转换为 2 字节。可以认为像 near、short、far 这些用在调用或转移中的修饰符意义就是数据类型转换。far 表示取 4 字节short 表示取 1 字节。 near 若加在寄存器前面如 call near ax表示在 ax 寄存器取 2 字节相当于给 ax 寄存器中的值做了类型转换。由于 near 的范围可正可负是个有符号数范围所以它不等同于数据类型 word。 6、实模式下的 ret call 指令用来执行一段新的代码它执行完目标函数后还是要回来的所以它得提前把回来的路返回地址记好。对于 CPU 来说它是靠程序计数器 PC 来指路的所以路就在 PC 中。由于随着函数嵌套调用的层数增加会有更多的返回地址需要保存。内存空间相对是无限的保存数量未知的返回地址比较理想。利用栈的后进先出的特性可以保证函数嵌套调用及嵌套返回顺序的一致性而且栈空间只受限于内存大小。所以 CPU 在栈中保留程序计数器 PC 的值。在 x86 中的程序计数器是 CSIP具体保留 IP 部分还是 CS 和 IP 都保留是要看目标函数的段基址是否和当前段基址一致是否跨段访问了。 call 指令只会留下返回地址后并踏上新的征程保留的返回地址是给 ret 或 retf 指令准备的在目标函数中必须有这两个指令之一CPU才能回来。 ret (return把当前栈顶寄存器 ss: sp 所指向的地址处的 2 字节 内容弹出栈并用它为 IP 寄存器赋值。ret 指令不管里面的内容是不是地址内容的正确性由程序员自己控制。ret 只置换了 IP 寄存器不用换段基址属于近返回。既然我们称之为弹出栈也就是说 ret 指令也要负责维护栈顶指针由于栈是从高地址往低地址发展所以被回收的栈顶空间应该是使 sp 指针值变大故 ret 指令会使 sp 指针2。 retf (return far是从栈顶取得 4 字节栈顶处的 2 字节用来替换 IP 寄存器另外的 2 字节用来替换 CS 寄存器。retf 也不会去检查从栈顶往上的 4 字节内容是不是偏移地址和段基址由程序员负责栈中数据的正确性。段寄存器都换了说明这属于远返回。retf 指令也要负责维护栈顶指针所以 retf 指令会使 sp 指针4。 【注】call 和 ret 配对用于近调用和近返回call far 和 retf 配对用于远调用和远返回。 7、实模式下的 call call意为呼叫、调用。在汇编言中用 call 命令实现一个函数的调用。在 8086 中 jmp 和 call 两个指令用于改变程序流程。区别是 jmp 属于一去不回头地去执行新的代码适用环境是 交接call 指令用于执行完一段分支后再回来的情况。 16位实模式相对近调用 指令格式 “call near 立即数地址”near 可省略。 此指令是个 3 字节指令0xe8 是此操作的操作码占 1 字节操作数占 2 字节。立即数地址可以是被调用的函数名、标号、立即数函数名同标号一样最终会被编译器转换为一个实际数字地址如 call near prog_name。 不直接、不间接 指令中的操作数是立即数是 call 指令相对于目标地址的偏移量是个地址差不是绝对地址。CPU 在实际执行中还要将此偏移量还原成绝对地址。需要转换不够直接操作数不是寄存器或内存不够间接。相对 “立即数地址” 是 call 指令相对于目标地址的偏移量。近跳转地址和当前指令在同一个段内只需给出段内偏移地址。操作数是个有符号数且又占 2 字节由于段是个 16 位大小的空间所以正负数的范围是 -32768~32767。 操作数的计算操作数目标地址当前指令地址3 call 相对近调用此指令机器码是 e8llhh占用 3 字节。其中 e8 是操作码表示相对近调用ll 表示操作数的低位hh 表示操作数的高位hhll 表示跳转目标为 4 位地址。由于 x86 平台是小端字节序故写成了 llhh即高位在高地址低位在低地址。这 4 位地址是个相对增量首先用目标函数的地址减去当前 call 指令的地址所得的差再减去此 call 指令机器码的大小最终的结果便是 call 指令中的操作数即与目标地址的相对地址增量。如 call proc_nameproc_name 是某函数名假如 call 所在的地址是 0x9事先知道 proc_name 所在的地址是 0x12此处的 call 是相对近转移机器码占 3 字节最终 call 的操作数是 0x12 - 0x9 - 3 0x6由于是小端字节序的原因低位在低地址高位在高地址最终的操作码是 e80600。这个值 0x6 不需要我们去算编译器会将函数的地址转换成相对地址。 【注】只要是 “相对”就是给出跳转指令对于当前指令的偏移量偏移量都是这么算的。 16位实模式间接绝对近调用 指令格式call 寄存器寻址 或 call 内存寻址near 可省略已省。 如 call axcall [0x1234]。不同指令形式对应不同的操作码call 内存寻址 对应的操作码是 ff16机器码是 ff1616 位内存地址。机器码除了与寻址方式有关外还和寄存器名称有关如 call ax 的机器码是 ffd0call cx 的机器码是 ffd1。此调用形式也是近调用near 可以省略并没有跨段所以 call 指令只要保留 IP 寄存器的值就好了将其压入栈后再用新的偏移地址替换 IP 的值。 间接call 寄存器寻址 或 call 内存寻址绝对直接给出目标地址近只需给出段内偏移地址 16位实模式直接绝对远调用 指令格式“call far 段基址立即数段内偏移地址立即数”。far 可省略 操作码是 0x9a。机器码是 0x9a 2 字节的偏移地址2 字节的段基址即偏移地址在前段基址在后和指令的调用形式是相反的。由于是远调用所以 CS 和 IP 都要用新的call 指令将来还是要回来的所以要在栈中保留回来的路即先把老的 CS 寄存器压入栈再把老的 IP 寄存器压入栈后用新的 CS 和 IP 寄存器替换从此开启新的旅途。 16位实模式间接绝对远调用 这和第 3 种的区别就是 直接 变 间接 了。也就是说段基址和段内偏移地址都不是立即数要么在内存中要么在寄存器中。可是段基址和段内偏移地址都是 16 位地址用一个寄存器肯定是盛不下了至少得用两个。寄存器资源还是非常珍贵的既然要用两个干脆一个都不用算啦所以这种间接绝对远调用的形式不支持寄存器寻址只支持内存寻址即段基址和段内偏移地址在内存中。 指令格式“call far 内存寻址“。far 不可省略否则就和间接绝对近调用一样了。 如 call far [bx]call far [0x1234]操作码是 ffle。在该内存中的内容大小是 4 字节此内容便是地址前低2字节是段内偏移地址后高2字节是段基址。 新的段基址和段内偏移既然是在内存中访问内存的话也要按照 段基址段内偏移地址 的形式去操作。例如上面的 call far [0x1234]由于没有段跨越前缀则将默认的段基址寄存器 ds*16 后再与 0x1234 相加得到的和为物理地址再到该物理地址处去读取新的偏移地址和段基址以该物理地址为起始的 2 个字节是段内偏移地址以该物理地址2为起始的 2 个字节是段基址。既然是段基址和段内偏移地址都要用新的CPU 为了记得回来的路先把老的 CS 寄存器压入栈再把老的 IP 寄存器压入栈保存起来再用新的段基址替换 CS新的段内偏移地址替换IP。 8、实模式下的 jmp 无条件跳转是指 生硬地 改变 CPU 航线将程序流转移到新的位置。jmp 转移指令只要更新 CSIP 寄存器或只更新 IP 寄存器就好了不需要保存它们的值。 16位实模式相对短转移 指令格式jmp short 立即数地址 。 操作数是个相对增量是个有符号数。相对短转移的机器码大小是 2 字节操作码是 0xeb可知其占 1 字节。操作数也占 1 字节。 不直接、不间接 同相对近调用相对操作数是个相对增量是个有符号数。短跳转地址和当前指令在同一个段内只需给出段内偏移地址。 短 体现在操作数中即跳转的范围只能是 1 字节有符号数所表示的范围即 -128~127。 操作数的计算操作数目标地址当前指令地址2 CPU 是要用绝对地址来寻址的目标地址操作数 当前指令地址 2所得的结果便是目标地址的绝对地址这样的地址 CPU 才能用。CPU 把求得的绝对地址载入 IP 寄存器。短转移目标地址和当前指令在同一个段内所以 CS 段寄存器不用修改CPU 就实现了向新位置的转移。 16位实模式相对近转移 同 “相对短转移” 相比操作数范围增大了由 8 位宽度变成了 16 位宽度操作数依然是地址相对量可正可负范围是 -32768~32767。其他没啥区别。 指令格式”jmp near 立即数地址”。 操作码是 0xe9。立即数地址也要经过编译器转换为地址偏移量再变成机器指令中的操作数。 操作数的计算操作数目标地址当前指令地址3。 16位实模式间接绝对近转移 同 jmp 相对近转移 相比目标地址是绝对地址未在指令中直接给出存在寄存器或内存中。 指令格式 “jmp near 寄存器寻址” 或者 “jmp near 内存寻址”near 可省。 若操作数在内存中在不使用段跨越前缀的情况下段基址寄存器是 DS。由于这也是近转移CS 寄存器的值不用修改CPU 只要用 16 位寄存器的值或内存中的 2 字节载入 IP 寄存器CPU 马上就被带到新的地址。 采用寄存器寻址的 jmp 指令其操作码是 0xff操作数随寄存器的不同而不同。采用内存寻址的jmp 指令其操作码还要看段基址寄存器用的是哪个。【P95】样例说明该点。 16位实模式直接绝对远转移 直接绝对远转移就是以立即数的形式给出目标地址的段基址和段内偏移地址。 指令格式“jmp 立即数形式的段基址立即数形式的段内偏移地址”。 例如 jmp0: 0x900其中 0 是段基址0x900 是段内偏移地址。由于是远转移所以 CPU 用操作数中的段基址载入 CS 寄存器用操作数中的偏移地址载入 IP 寄存器后才完成转移。 16位实模式间接绝对远转移 与 “间接绝对远调用” 一样由于操作数是两个数操作数只能放在内存中。为了指示 CPU 在内存中取 4 个字节需要在指令中用关键字 far即前两个字节是段内偏移地址后两个字节是段基址。若不指定则和第三种的 间接绝对近转移 一样只在内存处取 2 字节。 指令格式“jmp far 内存寻址”。far 不可省略。 由于操作数在内存中在不使用段跨越前缀的情况下段基址寄存器是 DS。此指令的操作数需要访问内存才能得到所以需要知道寻址方式。机器码与寻址方式有关要根据实际使用的数据段寄存器等情况来决定。同样由于是远转移CPU 的 CS 寄存器和 IP 寄存器都要修改成操作数中指定的值从而实现转移。修改方式请参考 “间接绝对远调用” 。 9、标志寄存器 flags 有条件转移指令的条件放在标志寄存器 flags 中。flags 寄存器是 16 位宽保护模式下对其扩展extend成 32 位的 eflags 寄存器。这些用于判断的条件本质上是上一条指令执行的结果。 flags 寄存器中存储的信息只是结果的特征即标志并不是真正的结果结果可以存储在内存中。这些标志告诉大家为了产生这个结果机器都做了什么。比如有时单纯的一个结果并不能让我们了解数据的全貌产生结果的过程中是否有溢出不知道这些怎么确定结果是正确的呢 无论逻辑多复杂都可以通过最简单的判断和转移来实现。判断哪里判断什么这个判断的对象就是标志寄存器中的标志位。 第 x 位标志位名称用途置 1置 0应用以下仅在 8088 以上 CPU 中有效0CF进位记录进位、借位最高位进位、借位检测无符号数加减法是否有溢出1空着2PF奇偶位标记结果低 8 位中 1 的个数个数为偶数数据传输开始时和结束后对比判断传输过程中是否出现错误3空着4AF辅助进位标志记录运算结果低 4 位的进、借位情况低半字节有进、借位5空着6ZF零标志位计算结果为 07SF符号标志位运算结果为负8TF陷阱标志位让 CPU 进入单步工作方式让 CPU 进入连续工作方式平时我们用的 debug 程序在单步调试时原理上就是让 TF 位为1。9IF中断标志位中断开启CPU 可以响应外部可屏蔽中断中断关闭CPU 不再响应来自外部的可屏蔽中断10DF方向标志位用于字符串操作指令中给地址的变化提供个方向。指令中的操作数地址会自动减少一个单位单位的大小取决于指令指令中的操作数地址会自动增加一个单位单位的大小取决于指令11OF溢出标志位标识计算的结果是否超过了数据类型可表示的范围超过有溢出专门用于检测有符号数运算结果是否有溢出现象以下仅在 80286 以上 CPU 中有效相对于8088它支持特权级和多任务12~13IOPL输入/输出特权级用在有特权级概念的 CPU 中有4个任务特权级特权级 0、特权级 1、特权级 2 和特权级 3。故 IOPL 要占用 2 位来表示这 4 种特权级14NT任务嵌套标志位8088 支持多任务一个任务就是一个进程当一个任务中又嵌套调用了另一个任务进程时15空着以下仅在 80386 以上 CPU 中有效16RF恢复标志位用于程序调试指示是否接受调试故障它需要与调试寄存器一起使用忽略调试故障接受调试故障17VM虚拟 8086 模式CPU 有了保护模式后为了兼容实模式下的用户程序可以在保护模式下运行实模式下的程序实模式下的程序不支持多任务而且程序中的地址就是真实的物理地址。所以在保护模式下每运行一个实模式下的程序就要为其虚拟一个实模式环境故称为虚拟模式以下仅在 80486 以上 CPU 中有效18AC对齐检查检查程序中的数据或指令其内存地址是否是偶数是否是16、32的整数倍没有余数进行地址对齐检查不检查以下仅在 80586奔腾以上 CPU 中有效19VIF虚拟中断标志位虚拟模式下的中断标志20VIP虚拟中断挂起标志位在多任务情况下为操作系统提供的虚拟中断挂起信息需要与VIF 位配合21ID识别标志位系统经常要判断 CPU 型号当前CPU支持 CPU id 指令可以获取 CPU 的型号、厂商等信息表示当前CPU不支持CPU id 指令22~31没有实际用途纯粹是占位用为了将来扩展 10、有条件转移 有条件转移是一个指令族在此简单称 jxx。 指令格式”jxx 目标地址“。 若条件满足则跳转到目标地址否则顺序执行下一条指令。目标地址只能是段内偏移地址。在实模式下由编译器根据当前指令与目标地址的偏移量自行将其编译成短转移或近转移。在保护模式下寄存器中宽度已经到了 32 位32 位的偏移地址可以访问到整个 32 位地线总线的 4GB 内存空间编译器不再区分转移方式。 条件转移指令一定得在某个能够影响标志位的指令之后进行。每执行一条指令标志寄存器中的相应位都会记录这条指令所带来的变化。条件转移指令判断的就是上一条指令对标志位的 影响这些 影响 就是条件即条件转移指令中所说的条件就是指标志寄存器中的标志位。 【注】表 3-12 要留个印象经常用的就两三个。 其他问题 【Q】有的编译器中还支持 segmentsegment 与 section 功能类似那么 segment 与 section 有什么区别【P67】 【A】【P25】 【Q】该页提到”平坦模型“什么是”平坦模型“【P70】 【A】【P12】 【Q】IA32 指令格式是怎么构成的【P71】 【A】【P71】 【Q】既然指令是存放在指令寄存器中的那指令中用到的数据存放在哪里【P71】 【A】存储单元的介绍【P71】
相关文章
-
如何制作h5做网站wordpress主机安装教程
如何制作h5做网站wordpress主机安装教程
- 技术栈
- 2026年03月21日
-
如何制作app软件下载舟山网站建设优化
如何制作app软件下载舟山网站建设优化
- 技术栈
- 2026年03月21日
-
如何制作apple pencil外链seo服务
如何制作apple pencil外链seo服务
- 技术栈
- 2026年03月21日
-
如何制作导航网站哈尔滨招聘网最新招聘信息网
如何制作导航网站哈尔滨招聘网最新招聘信息网
- 技术栈
- 2026年03月21日
-
如何制作钓鱼网站手机建站教程
如何制作钓鱼网站手机建站教程
- 技术栈
- 2026年03月21日
-
如何制作网站板块四川建设人才网网站
如何制作网站板块四川建设人才网网站
- 技术栈
- 2026年03月21日






