JMP

跳跃

stableVMJITAOTinstruction

编码

操作码指令Op/En64 位兼容/传统说明
EB cbJMP rel8D有效有效跳跃短,RIP = RIP + 8位移位符号扩展为64位.
E9 cwJMP rel16D不支持有效跳近、相对、相对于下一个指令的移位。 不支持64位模式 。
E9 cdJMP rel32D有效有效跳近,相对,RIP = RIP + 32位移位符号扩展为64位.
FF /4JMP r/m16M不支持有效跳近,绝对间接,地址=零扩展 r/m16. 不支持64位模式.
FF /4JMP r/m32M不支持有效跳近,绝对间接,地址以 r/m32 给出. 不支持64位模式.
FF /4JMP r/m64M有效不可编码跳近,绝对间接,RIP = 64-Bit 从寄存器或内存中抵消.
EA cdJMP ptr16:16Sinv.有效跳远,绝对,地址以 操作数 表示.
EA cpJMP ptr16:32Sinv.有效跳远,绝对,地址以 操作数 表示.
FF /5JMP m16:16M有效有效跳远,绝对间接,地址以m16:16给出.
FF /5JMP m16:32M有效有效跳远,绝对间接,地址以m16:32给出.
REX.W FF /5JMP m16:64M有效不可编码跳远,绝对间接,地址以m16:64给出.

操作数编码

每个模式对应上表 Op/En 列的一个取值,说明各操作数按书写顺序分别编码在指令的哪个字段,以及指令对它是读、是写还是两者兼有。

S

  1. Segment + Absolute Address

D

  1. offset操作码后的位移

M

  1. modrm.rm lecturaModRM 字节的 r/m 字段(第 2-0 位);当 mod 字段要求时,还包括 SIB 字节和位移

实测开销

正在从 arch-data 加载实测数据...

说明

将程序控制传输到指令流中不同的点而不记录返回信息. 目的地( 目标) 操作数 指定被跳转到的指令地址 。 这个操作数可以是即时值,通用寄存器,也可以是内存位置.

此指令可用于执行四种不同类型的跳跃:

CS寄存器),有时简称为区内跳.

相同的特权级别,有时也被称为间隙跳跃.

一个任务开关只能在保护模式中执行(参见第10章,Intel(R)64和IA-32架构软件开发者手册第3A卷,用于使用JMP指令执行任务开关的信息).

近与短跃. 当执行近跳时,处理器跳转到目标操作数指定的地址(在当前代码段内). 目标操作数指定了绝对抵消(即从代码段底部抵消)或相对抵消(与当前数字相对的签名移位)

EIP登记册中的指令指针值。 接近跳跃到相对偏移8位(rel8)被称为短跳. CS寄存器在近和短跳时不更改.

在通用寄存器或内存位置(r/m16或r/m32)中间接指定绝对偏移. 操作数大小属性决定目标操作数的大小(16或32位). 绝对偏移直接加载到 EIP 寄存器中. 如果 操作数 大小属性为 16,则EIP 寄存器的上两个字节被清除,导致 指令指针 最大大小为 16 比特.

相对偏移(rel8,rel16,或rel32)在组装代码中一般被指定为标签,但在机器代码级别上,它被编码为签名的8-,16-,或32位直接值. 此值被添加到 EIP 寄存器的值中 。 (此处,EIP注册簿包含JMP指令之后的指令地址). 在使用相对偏移时,操作码(对于短对近跳)和操作数大小属性(对于近相对跳)决定目标操作数的大小(8,16,或32位).

远跳在Real-Address或虚拟 8086 模式. 当在真地址或虚拟 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)和访问权限决定要执行的跳跃类型.

如果选中的描述符是用于代码段,则会执行一个在相同特权级别跳到代码段的远处. (如果选中的代码段处于不同的特权级别,并且代码段不符合规定,则生成一般保护例外. ) 保护模式中远跳到相同的特权级别与在真地址或虚拟 8086 模式中执行的高度相似. 目标操作数指定绝对远地址,或者直接用指针(ptr16:16或ptr16:32),或者间接用内存位置(m16:16或m16:32). 操作数大小属性决定了远地址中偏移(16或32位)的大小. 新的代码段选择子及其描述器被装入CS寄存器,指令的抵消被装入EIP寄存器. 请注意,调用闸门(在下段描述)也可以用于执行远程调用到同一特权级别的代码段. 使用这个机制提供了额外的间接级,也是在16位和32位代码段之间进行跳跃的首选方法.

在通过呼叫门执行远跳时,目标操作数指定的段选择子识别呼叫门. (目标操作数的偏移部分被忽略. )处理器然后跳到呼叫门描述符中指定的代码段,并在呼叫门中指定的偏移处开始执行指令. 没有堆栈开关发生 。 在这里,目标操作数也可以直接用指针(ptr16:16或ptr16:32)或间接用内存位置(m16:16或m16:32)指定呼叫门的远地址.

用 JMP 指令执行任务切换,与通过调用闸门执行跳跃有点相似. 在此,目标操作数指定任务门的段选择子用于切换任务(而目标操作数的抵消部分被忽略). 任务门依次指向任务TSS,它包含了任务代码和堆栈部分的段选择器. TSS中还包含了在任务中止前要执行的下一个指令的EIP值. 这个 指令指针 值被加载到 EIP 寄存器中, 以便任务在此下一个指令中重新开始执行 。

JMP指令也可以直接指定TSS的段选择子,这消除了任务门的间接性. 见Intel(R)64和IA-32 Architecture Software开发者手册第3A卷第10章,关于任务开关的力学的详细信息.

当执行一个 JMP 指令影响任务切换时,巢任务旗(NT)没有设置在 EFLAGS 寄存器中,新的 TSS 之前的任务链接字段没有装入旧任务中的 TSS 选择器. 因此,不能通过执行IRET指令来返回先前的任务。 使用 JMP 指令切换任务在这方面不同于 CALL 指令,该指令确实设置了 NT 旗并保存了上一个任务链接信息,允许使用 IRET 指令返回调用任务.

参见第6章"程序调用,中断,和例外"和第18章"控制流执行技术(CET)"在Intel(R)64和IA-32架构软件开发者手册第1卷,用于CET的细节.

在64比特模式。 指令的操作大小固定在64位. 如果选择者指向一个门,则RIP等于从门取出的64位移位;否则RIP等于从指令中引用的远指针中推算出的0位移位.

当FRED过渡被启用时,一个引用调用闸门的远 JMP的执行会导致一般保护例外,一个远 JMP的执行也会在CPL为0时进入兼容模式.

参见本节开头的汇总图,用于编码数据和限制.

指令令. 远跳之后的指示可能会在之前的指示完成执行之前从内存中获取,但是在远跳之前的所有指示完成执行之前,它们不会执行(甚至猜测)(后来的指示可能在执行之前,早期指示存储的数据已经在全球范围可见).

遵照近乎间接的JMP指令(即未达到目标的指令)依次执行的指令,可以推测. 如果软件需要防止(例如为了防止投机性执行侧通道),那么INT3或LFENCE指令操作码可以在近间接JMP之后放置,以阻止投机性执行.

行动

IF near jump
    IF 64-bit Mode
          THEN
                IF near relative jump
                 THEN
                      tempRIP := RIP + DEST; (* RIP is instruction following JMP instruction*)
                 ELSE (* Near absolute jump *)
                      tempRIP := DEST;
                FI;
          ELSE
                IF near relative jump
                 THEN
                      tempEIP := EIP + DEST; (* EIP is instruction following JMP instruction*)
                 ELSE (* Near absolute jump *)
                      tempEIP := DEST;
                FI;
    FI;

   IF (IA32_EFER.LMA = 0 or target mode = Compatibility mode) and tempEIP outside code segment limit

          THEN #GP(0); FI
    IF 64-bit mode and tempRIP is not canonical

          THEN #GP(0);
    FI;

   IF OperandSize = 32

           THEN
                EIP := tempEIP;

           ELSE

             IF OperandSize = 16
                  THEN (* OperandSize = 16 *)

                            EIP := tempEIP AND 0000FFFFH;

                   ELSE (* OperandSize = 64)


                            RIP := tempRIP;
                FI;
     FI;
    IF (JMP near indirect, absolute indirect)
          IF EndbranchEnabledAndNotSuppressed(CPL)
                IF CPL = 3

                      THEN
                            IF ( no 3EH prefix OR IA32_U_CET.NO_TRACK_EN == 0 )
                                  THEN
                                        IA32_U_CET.TRACKER = WAIT_FOR_ENDBRANCH
                            FI;

                      ELSE
                            IF ( no 3EH prefix OR IA32_S_CET.NO_TRACK_EN == 0 )
                                  THEN
                                        IA32_S_CET.TRACKER = WAIT_FOR_ENDBRANCH
                            FI;

                FI;
          FI;
    FI;
FI;

IF far jump and (PE = 0 or (PE = 1 AND VM = 1)) (* Real-address or virtual-8086 mode *)

     THEN
           tempEIP := DEST(Offset); (* DEST is ptr16:32 or [m16:32] *)
           IF tempEIP is beyond code segment limit
                THEN #GP(0); FI;
           CS := DEST(segment selector); (* DEST is ptr16:32 or [m16:32] *)

         IF OperandSize = 32

                 THEN
                      EIP := tempEIP; (* DEST is ptr16:32 or [m16:32] *)

              ELSE (* OperandSize = 16 *)

                      EIP := tempEIP AND 0000FFFFH; (* Clear upper 16 bits *)
           FI;
FI;

IF far jump and (PE = 1 and VM = 0)

(* IA-32e mode or protected mode, not virtual-8086 mode *)
     THEN
           IF effective address in the CS, DS, ES, FS, GS, or SS segment is illegal or segment selector in target operand NULL
                      THEN #GP(0); FI;
           IF segment selector index not within descriptor table limits
                THEN #GP(new selector); FI;
          Read type and access rights of segment descriptor;

        IF (IA32_EFER.LMA = 0)

                THEN
                      IF segment type is not a conforming or nonconforming code segment, call gate, task gate, or TSS
                            THEN #GP(segment selector); FI;

                ELSE
                      IF segment type is not a conforming or nonconforming code segment or call gate
                            THEN #GP(segment selector); FI;

          FI;
          Depending on type and access rights:

                GO TO CONFORMING-CODE-SEGMENT;
                GO TO NONCONFORMING-CODE-SEGMENT;
                GO TO CALL-GATE;
                GO TO TASK-GATE;


                GO TO TASK-STATE-SEGMENT;
     ELSE

           #GP(segment selector);
FI;
CONFORMING-CODE-SEGMENT:

   IF L-Bit = 1 and D-BIT = 1 and IA32_EFER.LMA = 1

          THEN GP(new code segment selector); FI;
     IF DPL > CPL

          THEN #GP(segment selector); FI;
    IF CR4.FRED = 1 and CPL = 0 and L-bit = 0

          THEN GP(new code segment selector); FI;
     IF segment not present

          THEN #NP(segment selector); FI;
    tempEIP := DEST(Offset);

   IF OperandSize = 16

           THEN tempEIP := tempEIP AND 0000FFFFH;
    FI;

   IF (IA32_EFER.LMA = 0 or target mode = Compatibility mode) and

    tempEIP outside code segment limit
          THEN #GP(0); FI

    IF tempEIP is non-canonical
          THEN #GP(0); FI;

    IF ShadowStackEnabled(CPL)
          IF (IA32_EFER.LMA and DEST(segment selector).L) = 0
                (* If target is legacy or compatibility mode then the SSP must be in low 4GB *)
                IF (SSP & 0xFFFFFFFF00000000 != 0)
                       THEN #GP(0); FI;
          FI;

    FI;
    CS := DEST[segment selector]; (* Segment descriptor information also loaded *)
    CS(RPL) := CPL
    EIP := tempEIP;
    IF EndbranchEnabled(CPL)

          IF CPL = 3
                THEN
                       IA32_U_CET.TRACKER = WAIT_FOR_ENDBRANCH
                       IA32_U_CET.SUPPRESS = 0
                ELSE
                       IA32_S_CET.TRACKER = WAIT_FOR_ENDBRANCH
                       IA32_S_CET.SUPPRESS = 0

          FI;
    FI;
END;
NONCONFORMING-CODE-SEGMENT:

   IF L-Bit = 1 and D-BIT = 1 and IA32_EFER.LMA = 1

          THEN GP(new code segment selector); FI;

   IF (RPL > CPL) OR (DPL  CPL)

          THEN #GP(code segment selector); FI;
    IF CR4.FRED = 1 and CPL = 0 and L-bit = 0

          THEN GP(new code segment selector); FI;
    IF segment not present

          THEN #NP(segment selector); FI;
    tempEIP := DEST(Offset);

   IF OperandSize = 16


           THEN tempEIP := tempEIP AND 0000FFFFH; FI;

   IF (IA32_EFER.LMA = 0 OR target mode = Compatibility mode)

    and tempEIP outside code segment limit
          THEN #GP(0); FI

    IF tempEIP is non-canonical THEN #GP(0); FI;
    IF ShadowStackEnabled(CPL)

          IF (IA32_EFER.LMA and DEST(segment selector).L) = 0
                (* If target is legacy or compatibility mode then the SSP must be in low 4GB *)
                IF (SSP & 0xFFFFFFFF00000000 != 0)
                       THEN #GP(0); FI;

          FI;
    FI;
    CS := DEST[segment selector]; (* Segment descriptor information also loaded *)
    CS(RPL) := CPL;
    EIP := tempEIP;
    IF EndbranchEnabled(CPL)

          IF CPL = 3
                THEN
                       IA32_U_CET.TRACKER = WAIT_FOR_ENDBRANCH
                       IA32_U_CET.SUPPRESS = 0
                ELSE
                       IA32_S_CET.TRACKER = WAIT_FOR_ENDBRANCH
                       IA32_S_CET.SUPPRESS = 0

          FI;
    FI;
END;

CALL-GATE:
    IF call gate DPL < CPL or call gate DPL < call gate segment-selector RPL or CR4.FRED = 1
                THEN #GP(call gate selector); FI;
    IF call gate not present
          THEN #NP(call gate selector); FI;
    IF call gate code-segment selector is NULL
          THEN #GP(0); FI;
    IF call gate code-segment selector index outside descriptor table limits
          THEN #GP(code segment selector); FI;
    Read code segment descriptor;
    IF code-segment segment descriptor does not indicate a code segment
    or code-segment segment descriptor is conforming and DPL > CPL

   or code-segment segment descriptor is non-conforming and DPL  CPL

                THEN #GP(code segment selector); FI;

   IF IA32_EFER.LMA = 1 and (code-segment descriptor is not a 64-bit code segment

    or code-segment segment descriptor has both L-Bit and D-bit set)
                THEN #GP(code segment selector); FI;

    IF code segment is not present
          THEN #NP(code-segment selector); FI;

     tempEIP := DEST(Offset);

    IF GateSize = 16

           THEN tempEIP := tempEIP AND 0000FFFFH; FI;

   IF (IA32_EFER.LMA = 0 OR target mode = Compatibility mode) AND tempEIP

    outside code segment limit
          THEN #GP(0); FI

    CS := DEST[SegmentSelector]; (* Segment descriptor information also loaded *)
    CS(RPL) := CPL;


    EIP := tempEIP;
    IF EndbranchEnabled(CPL)

          IF CPL = 3
                THEN
                      IA32_U_CET.TRACKER = WAIT_FOR_ENDBRANCH;
                      IA32_U_CET.SUPPRESS = 0
                ELSE
                      IA32_S_CET.TRACKER = WAIT_FOR_ENDBRANCH;
                      IA32_S_CET.SUPPRESS = 0

          FI;
    FI;
END;
TASK-GATE:
    IF task gate DPL < CPL
    or task gate DPL < task gate segment-selector RPL

          THEN #GP(task gate selector); FI;
    IF task gate not present

          THEN #NP(gate selector); FI;
    Read the TSS segment selector in the task-gate descriptor;
    IF TSS segment selector local/global bit is set to local
    or index not within GDT limits
    or descriptor is not a TSS segment
    or TSS descriptor specifies that the TSS is busy

          THEN #GP(TSS selector); FI;
     IF TSS not present

          THEN #NP(TSS selector); FI;
     SWITCH-TASKS to TSS;
     IF EIP not within code segment limit

          THEN #GP(0); FI;
END;
TASK-STATE-SEGMENT:

    IF TSS DPL < CPL
    or TSS DPL < TSS segment-selector RPL
    or TSS descriptor indicates TSS not available

          THEN #GP(TSS selector); FI;
    IF TSS is not present

          THEN #NP(TSS selector); FI;
    SWITCH-TASKS to TSS;
    IF EIP not within code segment limit

          THEN #GP(0); FI;
END;

受影响的旗帜

如果任务切换发生, 所有旗帜都会受到影响; 如果任务切换不发生, 任何旗帜都不会受到影响 。

异常

保护模式
#GP(0)如果在目标操作数中抵消,调用闸门,或TSS超出了代码段限制. 如果目标操作数中的段选择子,调用闸门,任务闸门,或TSS是NULL. 如果一个内存操作数的有效地址位于CS,DS,ES,FS,或GS段限制之外. 如果DS,ES,FS,或GS寄存器用于访问内存,并包含一个NULL 段选择子. 如果目标模式是兼容模式,SSP不是在低4GB.
#GP(selector)如果 段选择子 指数在描述表限制之外。如果 段选择子 在 目标操作数 中指的段描述符不是
#SS(0)用于符合码段,不符合码段,调用闸门,任务闸门,或任务#NP(选择器)状态段。
#PF(fault-code)如果一个不兼容码段的 DPL 不等于 CPL
#AC(0)(当不使用调用闸门时. ) 如果用于段段选择器的RPL大于
#UDCPL如果DPL对于符合规则的段比CPL如果DPL从呼叫门、任务门或TSS段描述符小于CPL或超过RPL呼叫门、任务门或TSS's 段选择子。如果调用闸门中选择者的段描述符没有表示它是代码段。如果调用闸门中的段描述符没有表示代码段。段选择子在任务门中不显示可用的TSS如果段选择子(单位:千美元)TSS为本地设置本地/ 全局位点。如果TSS部分描述符指定:TSS正在忙碌或无法使用。如果内存操作数有效地址在 SS 段限制之外。如果访问的代码段不在场。如果呼叫门、任务门或TSS不存在。如果页面错误发生。 如果启用对齐检查, 在当前特权级别为 3( 仅在从内存中获取目标时发生 ) 时使用不对齐的内存引用 。LOCK使用前缀。
实地址模式
#GP如果 内存操作数 有效地址位于 CS,DS,ES,FS 或 GS 分部限制之外,如果 内存操作数 有效地址位于 CS,DS,ES,FS 或 GS 分部限制之外.
#SS如果 内存操作数 的有效地址在 SS 段限制之外。
#UD如果使用 LOCK 前缀 。
虚拟 8086 模式
#GP(0)如果目标操作数超出代码段限制,如果内存操作数的有效地址在CS,DS,ES,FS或GS代码段限制之外.
#SS(0)如果 内存操作数 有效地址在 SS 段限制之外. #PF(fault-code) 如果 页面错误 发生.
#AC(0)如果启用对齐检查, 并进行不对齐的内存引用 。 (仅在从内存中获取目标时发生 。)
#UD如果使用 LOCK 前缀 。
兼容模式
与64位模式例外相同.
#GP(Selector)如果启用 FRED 转换, 选择器引用调用门 。
64 位模式
#GP(0)如果一个内存地址是非canonical的。如果在 目标操作数 中的目标抵消是非canonical的。如果在 目标操作数 中的目标抵消超过了新的代码段限制。如果 目标操作数 中的 段选择子 是 NULL。如果在 64 位门中的代码 段选择子 是 NULL。如果向兼容模式的过渡和 SSP 超出了 4GB 。
#GP(selector)如果代码段或64位调用闸门位于描述表限制之外,如果代码段或64位调用闸门重叠非调用空格.
#NP(selector)如果从64位调用门发出的段描述符处于非调用空间.
#UD如果 段选择子 在 目标操作数 中指的线段描述符不是
#PF(fault-code)用于符合码段,不符合码段,64位调用闸门。
#AC(0)如果段选择子输入目标操作数是一个代码段,并同时设置了 D 位和 L 位。如果DPL对于不符合规定的编码段,不等于CPL,或RPL给部分的段选择子大于CPL如果DPL对于符合规则的段比CPL如果DPL从64位调用门小于CPL或超过RPL64位调用门。如果一个64位调用门的上型字段不是0x0。如果段选择子如果选择器在64位门中指向的代码段描述器没有L位设定和D位清晰度。如果一个代码段描述器段选择子从64位调用闸门中不显示它是一个代码段。如果代码段不符合要求,CPL DPL如果代码段正在确认,CPL < DPL如果FRED启用了转换,选择器引用了一个调用门。如果FRED启用了过渡,CPL0,指令将输入兼容模式。如果一个代码段或64位调用闸门不存在。(只有64位模式)如果远程跳转到内存的绝对地址。如果LOCK前缀被使用。如果页面错误发生。如果启用了对齐检查,并且在当前特权级别为3时提供了不对齐的内存引用。

来源