鱼C论坛

 找回密码
 立即注册
查看: 3347|回复: 2

[学习笔记] 【原创】保护模式CALL指令-远跳转相关翻译资料(2)-CALL跳转过程逻辑说明

[复制链接]
发表于 2017-12-24 14:45:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 兰陵月 于 2017-12-24 16:03 编辑

逻辑代码段1
  1.         IF far call and (PE = 1 and VM = 0) (* Protected mode or IA-32e Mode, not virtual-8086 mode*)
  2.         THEN
  3.                 IF segment selector in target operand NULL
  4.                 THEN #GP(0); FI;
  5.                
  6.                 IF segment selector index not within descriptor table limits
  7.                 THEN #GP(new code segment selector); FI;
  8.                
  9.                 Read type and access rights of selected segment descriptor;

  10.                 IF IA32_EFER.LMA = 0
  11.                 THEN
  12.                         IF segment type is not a conforming or nonconforming code segment, call gate, task gate, or TSS
  13.                         THEN #GP(segment selector); FI;
  14.                 ELSE
  15.                         IF segment type is not a conforming or nonconforming code segment or 64-bit call gate,
  16.                         THEN #GP(segment selector); FI;
  17.                 FI;

  18.                 Depending on type and access rights:
  19.                 GO TO CONFORMING-CODE-SEGMENT;
  20.                 GO TO NONCONFORMING-CODE-SEGMENT;
  21.                 GO TO CALL-GATE;
  22.                 GO TO TASK-GATE;
  23.                 GO TO TASK-STATE-SEGMENT;
  24.         FI;
复制代码


                               
登录/注册后可看大图

                               
登录/注册后可看大图

逻辑代码段2【由逻辑代码段1第21行跳转而来】-跳转到一致代码段
  1.   CONFORMING-CODE-SEGMENT:
  2.     IF L bit = 1 and D bit = 1 and IA32_EFER.LMA = 1
  3.       THEN GP(new code segment selector); FI;
  4.    
  5.         IF DPL > CPL
  6.       THEN #GP(new code segment selector); FI;

  7.         IF segment not present
  8.       THEN #NP(new code segment selector); FI;
  9.    
  10.         IF stack not large enough for return address
  11.       THEN #SS(0); FI;
  12.    
  13.         tempEIP ← DEST(Offset);
  14.    
  15.         IF OperandSize = 16
  16.       THEN
  17.         tempEIP ← tempEIP AND 0000FFFFH; FI; (* Clear upper 16 bits *)
  18.    
  19.         IF (EFER.LMA = 0 or target mode = Compatibility mode) and (tempEIP outside new code segment limit)
  20.       THEN #GP(0); FI;

  21.         IF tempEIP is non-canonical
  22.       THEN #GP(0); FI;
  23.    
  24.         IF OperandSize = 32
  25.       THEN
  26.         Push(CS); (* Padded with 16 high-order bits *)
  27.         Push(EIP);
  28.         CS ← DEST(CodeSegmentSelector);
  29.         (* Segment descriptor information also loaded *)
  30.         CS(RPL) ← CPL;
  31.         EIP ← tempEIP;
  32.       ELSE
  33.         IF OperandSize = 16
  34.           THEN
  35.             Push(CS);
  36.             Push(IP);
  37.             CS ← DEST(CodeSegmentSelector);
  38.             (* Segment descriptor information also loaded *)
  39.             CS(RPL) ← CPL;
  40.             EIP ← tempEIP;
  41.           ELSE (* OperandSize = 64 *)
  42.             Push(CS); (* Padded with 48 high-order bits *)
  43.             Push(RIP);
  44.             CS ← DEST(CodeSegmentSelector);
  45.             (* Segment descriptor information also loaded *)
  46.             CS(RPL) ← CPL;
  47.             RIP ← tempEIP;
  48.         FI;
  49.     FI;
  50.   END;
复制代码

可以看到,上述各种情况下,CS段寄存器的RPL均被当前特权级CPL刷新,导致调用后的当前特权级CPL仍然为调用前的CPL的数值,程序跳转后运行在调用前的CPL级别下。

                               
登录/注册后可看大图

                               
登录/注册后可看大图

逻辑代码段3【由逻辑代码段1第22行跳转而来】-跳转到非一致代码段
  1. NONCONFORMING-CODE-SEGMENT:
  2.         IF L-Bit = 1 and D-BIT = 1 and IA32_EFER.LMA = 1
  3.           THEN GP(new code segment selector); FI;
  4.        
  5.         IF (RPL > CPL) or (DPL ≠ CPL)
  6.           THEN #GP(new code segment selector); FI;
  7.        
  8.         IF segment not present
  9.           THEN #NP(new code segment selector); FI;

  10.         IF stack not large enough for return address
  11.           THEN #SS(0); FI;

  12.         tempEIP ← DEST(Offset);

  13.         IF OperandSize = 16
  14.           THEN tempEIP ← tempEIP AND 0000FFFFH; FI; (* Clear upper 16 bits *)

  15.         IF (EFER.LMA = 0 or target mode = Compatibility mode) and (tempEIP outside new code segment limit)
  16.           THEN #GP(0); FI;

  17.         IF tempEIP is non-canonical
  18.           THEN #GP(0); FI;
  19.        
  20.         IF OperandSize = 32
  21.           THEN
  22.                 Push(CS); (* Padded with 16 high-order bits *)
  23.                 Push(EIP);
  24.                 CS ← DEST(CodeSegmentSelector);
  25.                 (* Segment descriptor information also loaded *)
  26.                 CS(RPL) ← CPL;
  27.                 EIP ← tempEIP;
  28.           ELSE       
  29.                 IF OperandSize = 16
  30.                   THEN
  31.                         Push(CS);
  32.                         Push(IP);
  33.                         CS ← DEST(CodeSegmentSelector);
  34.                         (* Segment descriptor information also loaded *)
  35.                         CS(RPL) ← CPL;
  36.                         EIP ← tempEIP;
  37.                   ELSE (* OperandSize = 64 *)
  38.                         Push(CS); (* Padded with 48 high-order bits *)
  39.                         Push(RIP);
  40.                         CS ← DEST(CodeSegmentSelector);
  41.                         (* Segment descriptor information also loaded *)
  42.                         CS(RPL) ← CPL;
  43.                         RIP ← tempEIP;
  44.                 FI;
  45.         FI;
  46.   END;
复制代码

可以看到,上述各种情况下,CS段寄存器的RPL均被当前特权级CPL刷新,导致调用后的当前特权级CPL仍然为调用前的CPL的数值,程序跳转后运行在调用前的CPL级别下。

                               
登录/注册后可看大图

                               
登录/注册后可看大图

逻辑代码段4【由逻辑代码段1第23行跳转而来】-通过调用门调用
  1.   CALL-GATE:
  2.     IF call gate (DPL < CPL) or (RPL > DPL)
  3.       THEN #GP(call-gate selector); FI;
  4.    
  5.         IF call gate not present
  6.       THEN #NP(call-gate selector); FI;
  7.    
  8.         IF call-gate code-segment selector is NULL
  9.       THEN #GP(0); FI;
  10.    
  11.         IF call-gate code-segment selector index is outside descriptor table limits
  12.       THEN #GP(call-gate code-segment selector); FI;
  13.    
  14.         Read call-gate code-segment descriptor;
  15.    
  16.         IF call-gate code-segment descriptor does not indicate a code segment
  17.        or call-gate code-segment descriptor DPL > CPL
  18.       THEN #GP(call-gate code-segment selector); FI;
  19.    
  20.         IF IA32_EFER.LMA = 1 AND (call-gate code-segment descriptor is
  21.        not a 64-bit code segment or call-gate code-segment descriptor has both L-bit and D-bit set)
  22.       THEN #GP(call-gate code-segment selector); FI;
  23.    
  24.         IF call-gate code segment not present
  25.       THEN #NP(call-gate code-segment selector); FI;
  26.    
  27.         IF call-gate code segment is non-conforming and DPL < CPL
  28.       THEN go to MORE-PRIVILEGE;
  29.       ELSE go to SAME-PRIVILEGE;
  30.     FI;
  31.   END;
复制代码


                               
登录/注册后可看大图

                               
登录/注册后可看大图

逻辑代码段5【由逻辑代码段4第28行跳转而来】-通过调用门(低特权级调用高特权级代码)
  1.   MORE-PRIVILEGE:
  2.     IF current TSS is 32-bit
  3.       THEN
  4.         TSSstackAddress ← (new code-segment DPL*8) + 4;
  5.         IF (TSSstackAddress + 5) > current TSS limit
  6.           THEN #TS(current TSS selector); FI;
  7.         NewSS ← 2 bytes loaded from (TSS base + TSSstackAddress + 4);
  8.         NewESP ← 4 bytes loaded from (TSS base + TSSstackAddress);
  9.       ELSE
  10.         IF current TSS is 16-bit
  11.           THEN
  12.             TSSstackAddress ← (new code-segment DPL*4) + 2
  13.             IF (TSSstackAddress + 3) > current TSS limit
  14.               THEN #TS(current TSS selector); FI;
  15.             NewSS ← 2 bytes loaded from (TSS base + TSSstackAddress + 2);
  16.             NewESP ← 2 bytes loaded from (TSS base + TSSstackAddress);
  17.           ELSE (* current TSS is 64-bit *)
  18.             TSSstackAddress ← (new code-segment DPL*8) + 4;
  19.             IF (TSSstackAddress + 7) > current TSS limit
  20.               THEN #TS(current TSS selector); FI;
  21.             NewSS ← new code-segment DPL; (* NULL selector with RPL = new CPL *)
  22.             NewRSP ← 8 bytes loaded from (current TSS base + TSSstackAddress);
  23.         FI;
  24.     FI;
  25.     IF IA32_EFER.LMA = 0 and NewSS is NULL
  26.       THEN #TS(NewSS); FI;
  27.     Read new code-segment descriptor and new stack-segment descriptor;
  28.     IF IA32_EFER.LMA = 0 and
  29.            (NewSS RPL ≠ new code-segment DPL or
  30.            new stack-segment DPL ≠ new code-segment DPL or
  31.            new stack segment is not a writable data segment)
  32.       THEN #TS(NewSS); FI
  33.     IF IA32_EFER.LMA = 0 and new stack segment not present
  34.       THEN #SS(NewSS); FI;
  35.     IF CallGateSize = 32
  36.       THEN
  37.         IF new stack does not have room for parameters plus 16 bytes
  38.           THEN #SS(NewSS); FI;
  39.         IF CallGate(InstructionPointer) not within new code-segment limit
  40.           THEN #GP(0); FI;
  41.         SS ← newSS; (* Segment descriptor information also loaded *)
  42.         ESP ← newESP;
  43.         CS:EIP ← CallGate(CS:InstructionPointer);
  44.         (* Segment descriptor information also loaded *)
  45.         Push(oldSS:oldESP); (* From calling procedure *)
  46.         temp ← parameter count from call gate, masked to 5 bits;
  47.         Push(parameters from calling procedure’s stack, temp)
  48.         Push(oldCS:oldEIP); (* Return address to calling procedure *)
  49.       ELSE
  50.         IF CallGateSize = 16
  51.           THEN
  52.             IF new stack does not have room for parameters plus 8 bytes
  53.               THEN #SS(NewSS); FI;
  54.             IF (CallGate(InstructionPointer) AND FFFFH) not in new code-segment limit
  55.               THEN #GP(0); FI;
  56.             SS ← newSS; (* Segment descriptor information also loaded *)
  57.             ESP ← newESP;
  58.             CS:IP ← CallGate(CS:InstructionPointer);
  59.             (* Segment descriptor information also loaded *)
  60.             Push(oldSS:oldESP); (* From calling procedure *)
  61.             temp ← parameter count from call gate, masked to 5 bits;
  62.             Push(parameters from calling procedure’s stack, temp)
  63.             Push(oldCS:oldEIP); (* Return address to calling procedure *)
  64.           ELSE (* CallGateSize = 64 *)
  65.             IF pushing 32 bytes on the stack would use a non-canonical address
  66.               THEN #SS(NewSS); FI;
  67.             IF (CallGate(InstructionPointer) is non-canonical)
  68.               THEN #GP(0); FI;
  69.             SS ← NewSS; (* NewSS is NULL)
  70.             RSP ← NewESP;
  71.             CS:IP ← CallGate(CS:InstructionPointer);
  72.             (* Segment descriptor information also loaded *)
  73.             Push(oldSS:oldESP); (* From calling procedure *)
  74.             Push(oldCS:oldEIP); (* Return address to calling procedure *)
  75.         FI;
  76.     FI;
  77.     CPL ← CodeSegment(DPL)
  78.     CS(RPL) ← CPL
  79. END;
复制代码

可以看到,各种检查通过后,目标代码段的DPL数值被传送给了当前特权级CPL(第77行),然后再用CPL的数值刷新了CS段寄存器的RPL数值(第78行)。所以程序调用后的当前特权级CPL数值是目标代码段的特权级,而不是程序调用前的特权级,这样程序由当前代码的低特权级提升到了目标代码的高特权级,这是唯一的可以提升当前特权级CPL的情况

                               
登录/注册后可看大图

                               
登录/注册后可看大图

逻辑代码段6【由逻辑代码段4第2行跳转而来】-通过调用门(特权级相同)
  1.   SAME-PRIVILEGE:
  2.     IF CallGateSize = 32
  3.       THEN
  4.         IF stack does not have room for 8 bytes
  5.           THEN #SS(0); FI;
  6.         IF CallGate(InstructionPointer) not within code segment limit
  7.           THEN #GP(0); FI;
  8.         CS:EIP ← CallGate(CS:EIP) (* Segment descriptor information also loaded *)
  9.         Push(oldCS:oldEIP); (* Return address to calling procedure *)
  10.       ELSE
  11.         If CallGateSize = 16
  12.           THEN
  13.             IF stack does not have room for 4 bytes
  14.               THEN #SS(0); FI;
  15.             IF CallGate(InstructionPointer) not within code segment limit
  16.               THEN #GP(0); FI;
  17.             CS:IP ← CallGate(CS:instruction pointer);
  18.             (* Segment descriptor information also loaded *)
  19.             Push(oldCS:oldIP); (* Return address to calling procedure *)
  20.           ELSE (* CallGateSize = 64)
  21.             IF pushing 16 bytes on the stack touches non-canonical addresses
  22.               THEN #SS(0); FI;
  23.             IF RIP non-canonical
  24.               THEN #GP(0); FI;
  25.             CS:IP ← CallGate(CS:instruction pointer);
  26.             (* Segment descriptor information also loaded *)
  27.             Push(oldCS:oldIP); (* Return address to calling procedure *)
  28.         FI;
  29.     FI;
  30.     CS(RPL) ← CPL
  31.   END;
复制代码

可以看到,上述各种情况下,CS段寄存器的RPL被当前特权级CPL刷新,导致调用后的当前特权级CPL仍然为调用前的CPL的数值,程序跳转后运行在调用前的CPL级别下。

                               
登录/注册后可看大图

                               
登录/注册后可看大图

逻辑代码段7【由逻辑代码段1第24行跳转而来】-跳转到任务门
  1.   TASK-GATE:
  2.     IF task gate DPL < CPL or RPL
  3.       THEN #GP(task gate selector); FI;
  4.     IF task gate not present
  5.       THEN #NP(task gate selector); FI;
  6.     Read the TSS segment selector in the task-gate descriptor;
  7.     IF TSS segment selector local/global bit is set to local
  8.        or index not within GDT limits
  9.       THEN #GP(TSS selector); FI;
  10.     Access TSS descriptor in GDT;
  11.     IF TSS descriptor specifies that the TSS is busy (low-order 5 bits set to 00001)
  12.       THEN #GP(TSS selector); FI;
  13.     IF TSS not present
  14.       THEN #NP(TSS selector); FI;
  15.     SWITCH-TASKS (with nesting) to TSS;
  16.     IF EIP not within code segment limit
  17.       THEN #GP(0); FI;
  18.   END;
复制代码


                               
登录/注册后可看大图

                               
登录/注册后可看大图

逻辑代码段8【由逻辑代码段1第25行跳转而来】-直接跳转到任务状态段TSS
  1.   TASK-STATE-SEGMENT:
  2.     IF TSS DPL < CPL or RPL
  3.        or TSS descriptor indicates TSS not available
  4.       THEN #GP(TSS selector); FI;
  5.     IF TSS is not present
  6.       THEN #NP(TSS selector); FI;
  7.     SWITCH-TASKS (with nesting) to TSS;
  8.     IF EIP not within code segment limit
  9.       THEN #GP(0); FI;
  10.   END;
复制代码

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2017-12-24 16:08:33 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-12-24 16:34:32 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-24 16:13

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表