diff --git "a/Intel \346\211\213\345\206\214\344\270\255\346\226\207\347\211\210/\345\215\267\344\272\214\357\274\232\346\214\207\344\273\244\351\233\206\345\217\202\350\200\203.md" "b/Intel \346\211\213\345\206\214\344\270\255\346\226\207\347\211\210/\345\215\267\344\272\214\357\274\232\346\214\207\344\273\244\351\233\206\345\217\202\350\200\203.md" index bc607aa..9ba7631 100644 --- "a/Intel \346\211\213\345\206\214\344\270\255\346\226\207\347\211\210/\345\215\267\344\272\214\357\274\232\346\214\207\344\273\244\351\233\206\345\217\202\350\200\203.md" +++ "b/Intel \346\211\213\345\206\214\344\270\255\346\226\207\347\211\210/\345\215\267\344\272\214\357\274\232\346\214\207\344\273\244\351\233\206\345\217\202\350\200\203.md" @@ -6,6 +6,113 @@ # 第三章 Instruction Set Reference, A-L +## 3.2 指令集( A-L ) +###JMP指令 +[@翻译人:xiaotianZhang456] +描述 + 将程序控制转移到指令流的不同点,不记录任何返回信息。它的目的(目标)操作数为将要跳转的指令的地址。该操作数可以是立即数、通用寄存器和内存位置。 + 这个指令用于执行四种不同类型的跳转: + • 近跳转,跳转到当前代码段(当前 CS 寄存器指向的段)内的指令,有时称为段内跳转。 + • 短跳转,跳转范围被限制在当前 EIP 寄存器的值的 -128 到 +128 之间。 + • 远跳转,跳转到与当前代码的不同段,但具有相同特权级别的指令,有时称为段间跳转指令。 + • 任务切换,跳转到位于不同任务中的指令。 + 任务切换只能在保护模式下执行(请参阅 Intel® 64 位和 IA-32 软件架构开发者手册,卷 3A 中的第 7 章) + 近跳转和短跳转。执行近跳转的时候,处理器跳转(在当前代码段内)到目标操作数指定的地址。目标操作数指定一个绝对偏移量(从代码段基址开始的偏移量)或相对偏移量(相对于 EIP 寄存器中指令指针当前值 +的有符号偏移量)。近跳转跳转到 8 位相对偏移量( rel8 )被称为短跳转。 CS 寄存器在近跳转和短跳转时不会发生变化。 + 绝对偏移量在通用寄存器或内存位置( r/m16 或 r/m32 )中间接指定。操作数尺寸属性决定目标操作数的大小( 16 位或 32 位)。绝对偏移量直接加载到 EIP 寄存器中。如果操作数的尺寸属性是16 , EIP +寄存器的高两个字节被清零,于是指令指针的最大值为 16 位。 + 相对偏移量( rel8 , rel16 ,或 rel32 )通常在汇编代码中指定为标签,但在机器码级别被编码成一个有符号的 8 位、 16 位或 32 位立即数。相对偏移量与 EIP 寄存器中的值相加,并加载到 EIP 寄存器 +中。( EIP 寄存器包含 JMP 指令后的指令地址)使用相对偏移量时,操作码(对于短跳转和近跳转)和操作数尺寸属性(对于近相对跳转)决定目标操作数的大小( 8 位、 16 位 或 32 位)。 + 实地址模式或 Virtual-8086 模式下的远跳转。 在实地址模式或 Virtual-8086 模式下执行远跳转指令时,处理器跳转到目标操作数指定的代码段和偏移量。目标操作数直接用指针( ptr16:16 或 ptr16:32 ) +或间接用内存位置( m16:16 或 m16:32 )指定绝对远地址。用指针方法,在指令中用一个 4 字节( 16 位操作数尺寸)或 6 字节( 32 位操作数尺寸)的远地址立即数编码所调用的处理程序的段和地址。用间接方 +法,目标操作数指定一个包含 4 字节( 16 位操作数尺寸)或 6 字节( 32 位操作数尺寸)的远地址的内存位置。CS 和 EIP 寄存器直接加载远地址。如果操作数尺寸属性是 16 ,EIP 寄存器的高两个字节被清零。 + 保护模式下的远跳转。处理器运行在保护模式下时, JMP 指令用于完成以下三种类型的远跳转: + • 远跳转到一致或非一致的代码段。 + • 通过调用门进行远跳转。 + • 任务切换。 + ( JMP 指令不能实现权限间的远跳转) + 在保护模式下,处理器通常使用远地址的段选择子部分来访问 GDT 和 LDT 中相应的描述符。描述符类型(代码段,调用门,任务门或 TSS )和访问权限决定要执行的跳转类型。 + 如果所选描述符用于代码段,则执行同一特权级别的代码段的远跳转。(如果选择的代码段位于不同的特权级别且代码段是非一致的,产生一个通用保护异常。)保护模式下远跳转到相同的特权级别和实地址模式 +或 virtual-8086 模式下的执行非常相似。目标操作数直接用指针( ptr16:16 或 ptr16:32 )或间接用内存位置( m16:16 或 m16:32 )指定一个绝对远地址。操作数尺寸属性决定远地址中偏移量的大小( 16 或 32 字节)。CS 寄存器加载新的代码段选择子和他的描述符,EIP 寄存器加载指令中的偏移量。值得注意的是,调用门也可以对同一特权级别的代码段执行远调用。用这种机制提供一个额外的间接级别,而且是在 16 位代码段和 32 位代码段之间跳转的首选方法。 + 通过调用门执行远跳转时,由目标操作数指定的段选择子标识调用门。(目标操作数的偏移量部分被忽略)然后处理器跳转到调用门描述符指定的代码段,并开始执行调用门中指定的偏移量处的指令。不会发生栈切换。同样,目标操作数可以直接用指针( ptr16:16 或 ptr16:32 )或间接用内存位置( m16:16 或 m16:32 )指定调用门的远地址。 + 通过跳转指令执行任务切换和通过调用门执行跳转有一点类似。这里的目标操作数指定被切换到的任务的任务门的段选择子(目标操作数的偏移部分被忽略)。任务门又指向任务的 TSS 它包含任务 +代码和堆栈段的段选择子。 TSS 也包含任务被挂起前即将被执行的下一条指令的 EIP 值。指令的指针被加载到 EIP 寄存器中以便任务在下一条指令中再次开始执行。 + JMP指令也可以直接指定 TSS 的段选择子,省去了任务门的间接性。请参阅卷 3A , Intel® 64 和 IA-32 软件架构开发手册第七章,获取任务切换机制的详细信息。 + 需要注意的是,当你在任务切换时用 JMP 指令执行,EFLAGS 寄存器中未设置嵌套任务标志( NT ),且新的 TSS 之前的任务链接字段未加载旧任务的 TSS 段选择子。因此不能通过执行 IRET 指令 +返回到前一个任务。用 JMP 指令切换任务与 CALL 指令不同,后者设置 NT 标志位且保存之前的任务链接信息,允许使用 IRET 指令返回调用任务。 + 请参阅英特尔 ®64 位和 IA-32 软件架构开发手册卷一第六章“过程调用,中断和异常” 和第十八章“控制流执行技术( CET )”,了解 CET 的细节。 + 在 64 位模式下,指令的运算大小固定为 64 位。如果一个选择子指向一个门,那么 RIP 等于从门中取出的 64 位位移;否则 RIP 等于指令中引用的远指针的零扩展偏移量。有关编码数据和限制, +请参阅本节开头的摘要图表。 + 指令排序。在较早的指令完成之前,可以从内存中提取紧跟远跳转的指令。但在远跳转之前的所有指令执行完之前,他们不会执行(即使预测的)(较晚的指令可能会在较早的指令存储的数据变得全局可见之前 +执行)。 + 某种情况可能导致下一条顺序指令在间接近跳转被预测执行之后执行。如果软件需要阻止它(例如,为了阻止一个预测执行侧通道),可以在近间接 JMP 之后放置一个 INT3 或 LFENCE 指令码以阻止预测执行。 + 操作 + 受影响的标志位 + 如果发生任务切换,所有标志位都会受到影响,如果没有发生任务切换,则不影响任何标志位。 + 保护模式异常 + #GP( 0 ) 如果目标操作数、调用门或 TSS 中的偏移量超出代码段限制。 + 如果目的操作数的段选择子、调用门、任务门或 TSS 为空。 + 如果内存操作数有效地址超出 CS , DS , ES , FS , 或 GS 段的限制。 + 如果 DS , ES , FS 或 GS 寄存器用于访问内存,且它包含一个空的段选择子。 + 如果目标模式是兼容模式并且 SSP 不是低 4GB 。 + #GP(选择子) 如果段选择子索引超出描述符表限制。 + 如果目标操作数中的段选择子指向的段描述符不适用于一致代码段、非一致代码段、调用门、任务门或任务状态段。 + 如果非一致代码段的 DPL 不等于 CPL(不使用调用门时)。如果段的段选择子的 RPL 大于 CPL 。 + 如果非一致代码段的 DPL 大于 CPL 。 + 如果来自调用门、任务门或 TSS 段描述符的 DPL 小于 CPL 或小于调用门、任务门或 TSS 段选择子的 RPL 。 + 如果调用门的段选择子的段描述符没有表明它是一个代码段。 + 如果任务门的段选择子的段描述符没有表明一个可用的 TSS 。 + 如果 TSS 的段选择子将其本地或全局位设置为本地。 + 如果 TSS 段描述符指定的 TSS 正忙或不可用。 + #SS( 0 ) 如果内存操作数有效地址超出 SS 段限制。 + #NP(选择子) 如果正在访问的代码段不存在。 + 如果调用门、任务门或 TSS 不存在。 + #PF(故障码) 如果发生页面错误。 + #AC( 0 ) 如果启用对齐检查并在当前权限级别为 3 时进行未对齐的内存引用。(仅在从内存中取目标时发生) + #UD 如果启用 LOCK 前缀。 + + 实地址模式异常 + #GP( 0 ) 如果内存操作数的有效地址超出 CS , DS , ES , FS 或 GS 段的限制。 + 如果内存操作数的有效地址超出 CS , DS , ES , FS 或 GS 段的限制。 + #SS( 0 ) 如果内存操作数的有效地址超出 SS 段的限制。 + #UD 如果启用 LOCK 前缀。 + + Virtual-8086 模式异常 + #GP( 0 ) 如果目标操作数超出代码段限制。 + #SS( 0 ) 如果内存操作数的有效地址超出 SS 段限制。 + #AC( 0 ) 如果对齐检查开启且引用了未对齐的内存。(只有从内存中取目标时发生) + #UD 如果启用 LOCK 前缀。 + + 兼容模式异常 + 和 64 位模式异常相同。 + + 64 位模式异常 + #GP(0) 如果内存地址是非标准的。 + 如果目的操作数的目标偏移量是非标准的。 + 如果目的操作数的目标偏移量超出新的代码段限制。 + 如果目的操作数中的段选择子为空。 + 如果 64 位门中的代码段选择子为空。 + 如果转换到兼容模式且 SSP 超过 4GB 。 + #GP(选择子) 如果代码段或 64 位调用门超出描述符表的限制。 + 如果代码段或 64 位调用门与非标准空间重叠。 + 如果 64 位调用门的段描述符在非标准空间。 + 如果目的操作数中的段选择子指向的段描述符不是用于一致性代码段、非一致性代码段、64 位调用门。 + 如果目的操作数中的段选择子指向的段描述符是一个代码段,且 D 和 L 位置 1 。 + 如果非一致代码段的 DPL 不等于 CPL ,或段的段选择子的 RPL 大于 CPL 。 + 如果非一致性代码的 DPL 大于 CPL 。 + 如果来自 64 位调用门的 DPL 小于 CPL 或小于 64 位调用门的 RPL 。 + 如果 64 位调用门的上层类型字段不是 0x0 。 + 如果 64 位调用门的段选择子超出描述符表的限制。 + 如果 64 位门的选择子指向的代码段描述符没有给 L 位置 1 ,给 D 位清零。 + 如果 64 位调用门的段选择子的段描述符没有指出它是一个代码段。 + 如果代码段是非一致的且 CP ≠ DPL 。 + 如果代码段是一致性的且 CPL < DPL 。 + #NP(选择子) 如果代码段或 64 位调用门不存在。 + #UD(仅 64 位模式) 如果一个远跳转直接跳到内存中的绝对地址。 + 如果启用 LOCK 前缀。 + #PF(故障码) 如果发生页面错误。 + #AC( 0 ) 如果启用对齐检查并在当前特权级别为 3 时进行未对齐的内存引用。 + # 第四章 Instruction Set Reference, M-U # 第五章 Instruction Set Reference, V-Z