1
각 데이터 조각이 스택에서 사용하는 바이트의 크기를 알고 싶습니다. 권한 수준이 대답에 어떤 영향을 줍니까?IA32 CPU, 보호 모드 : 인터럽트 발생시 어떤 데이터가 스택에 저장됩니까?
각 데이터 조각이 스택에서 사용하는 바이트의 크기를 알고 싶습니다. 권한 수준이 대답에 어떤 영향을 줍니까?IA32 CPU, 보호 모드 : 인터럽트 발생시 어떤 데이터가 스택에 저장됩니까?
짧은 대답은 : 인터럽트가 높은 privelege 수준에
경우, SS와 ESP는 각각 4 바이트를 소모 스택에 푸시됩니다. 같은 단계에서이 단계는 건너 뜁니다.
그런 다음 EFLAGS, CS 및 EIP가 각각 4 바이트를 사용하여 스택으로 푸시됩니다. 따라서 스택에 20 바이트가있을 가능성이 큽니다.
작업 게이트, 결함, 문맥 x86/x64 Instruction Set Reference에서, 의사 코드에 너무 오래 답을 등 전환을위한 많은 complicted execptions과 규칙이 있습니다
(* The following operational description applies not only to the INT n and INTO instructions, but also to external interrupts, nonmaskable interrupts (NMIs), and exceptions. Some of these events push onto the stack an error code. *)
(* The operational description specifies numerous checks whose failure may result in delivery of a nested exception. In these cases, the original event is not delivered. *)
(* The operational description specifies the error code delivered by any nested exception. In some cases, the error code is specified with a pseudofunction error_code(num, idt, ext), where idt and ext are bit values. The pseudofunction produces an error code as follows: *)
(* (1) if idt is 0, the error code is (num & FCH) | ext; *)
(* (2) if idt is 1, the error code is (num << 3) | 2 | ext. *)
(* In many cases, the pseudofunction error_code is invoked with a pseudovariable EXT. The value of EXT depends on the nature of the event whose delivery encountered a nested exception: if that event is a software interrupt, EXT is 0;otherwise, EXT is 1. *)
IF PE = 0
GOTO REAL-ADDRESS-MODE;
ELSE
IF PE = 1
IF (VM = 1 and IOPL < 3 AND INT n)
#GP(0); (* Bit 0 of error code is 0 because INT n *)
ELSE
(* Protected mode, IA-32e mode, or virtual-8086 mode interrupt *)
IF (IA32_EFER.LMA = 0)
(* Protected mode, or virtual-8086 mode interrupt *)
GOTO PROTECTED-MODE;
ELSE
(* IA-32e mode interrupt *)
GOTO IA-32e-MODE;
FI;
FI;
FI;
FI;
REAL-ADDRESS-MODE:
IF ((vector_number << 2) + 3) is not within IDT limit
#GP;
FI;
IF stack not large enough for a 6-byte return information
#SS;
FI;
Push (EFLAGS[15:0]);
IF = 0; (* Clear interrupt flag *)
TF = 0; (* Clear trap flag *)
AC = 0; (* Clear AC flag *)
Push(CS);
Push(IP);
(* No error codes are pushed in real-address mode *)
CS = IDT(Descriptor (vector_number << 2), selector));
EIP = IDT(Descriptor (vector_number << 2), offset)); (* 16 bit offset AND 0000FFFFH *)
END;
PROTECTED-MODE:
IF ((vector_number << 3) + 7) is not within IDT limits or selected IDT descriptor is not an interrupt-, trap-, or task-gate type
#GP(error_code(vector_number, 1, EXT));
FI;
(* idt operand to error_code set because vector is used *)
IF software interrupt (* Generated by INT n, INT3, or INTO *)
IF gate DPL < CPL (* PE = 1, DPL < CPL, software interrupt *)
#GP(error_code(vector_number, 1, 0));
FI;
(* idt operand to error_code set because vector is used *)
(* ext operand to error_code is 0 because INT n, INT3, or INTO *)
FI;
IF gate not present
#NP(error_code(vector_number, 1, EXT));
FI;
(* idt operand to error_code set because vector is used *)
IF task gate (* Specified in the selected interrupt table descriptor *)
GOTO TASK-GATE;
ELSE
GOTO TRAP-OR-INTERRUPT-GATE; (* PE = 1, trap/interrupt gate *)
FI;
END;
IA-32e-MODE:
IF INTO and CS.L = 1 (64-bit mode)
#UD;
FI;
IF ((vector_number << 4) + 15) is not in IDT limits or selected IDT descriptor is not an interrupt-, or trap-gate type
#GP(error_code(vector_number, 1, EXT));
(* idt operand to error_code set because vector is used *)
FI;
IF software interrupt (* Generated by INT n, INT 3, or INTO *)
IF gate DPL < CPL (* PE = 1, DPL < CPL, software interrupt *)
#GP(error_code(vector_number, 1, 0)); (* idt operand to error_code set because vector is used *)
(* ext operand to error_code is 0 because INT n, INT3, or INTO *)
FI;
FI;
IF gate not present
#NP(error_code(vector_number, 1, EXT));
(* idt operand to error_code set because vector is used *)
FI;
GOTO TRAP-OR-INTERRUPT-GATE; (* Trap/interrupt gate *)
END;
TASK-GATE: (* PE = 1, task gate *)
Read TSS selector in task gate (IDT descriptor);
IF local/global bit is set to local or index not within GDT limits
#GP(error_code(TSS selector, 0, EXT));
FI; (* idt operand to error_code is 0 because selector is used *)
Access TSS descriptor in GDT;
IF TSS descriptor specifies that the TSS is busy (low-order 5 bits set to 00001)
#GP(TSS selector, 0, EXT));
FI; (* idt operand to error_code is 0 because selector is used *)
IF TSS not present
#NP(TSS selector, 0, EXT));
FI; (* idt operand to error_code is 0 because selector is used *)
SWITCH-TASKS (with nesting) to TSS;
IF interrupt caused by fault with error code
IF stack limit does not allow push of error code
#SS(EXT);
FI;
Push(error code);
FI;
IF EIP not within code segment limit
#GP(EXT);
FI;
END;
TRAP-OR-INTERRUPT-GATE:
Read new code-segment selector for trap or interrupt gate (IDT descriptor);
IF new code-segment selector is NULL
#GP(EXT);
FI; (* Error code contains NULL selector *)
IF new code-segment selector is not within its descriptor table limits
#GP(error_code(new code-segment selector, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
Read descriptor referenced by new code-segment selector;
IF descriptor does not indicate a code segment or new code-segment DPL > CPL
#GP(error_code(new code-segment selector, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
IF new code-segment descriptor is not present,
#NP(error_code(new code-segment selector, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
IF new code segment is non-conforming with DPL < CPL
IF VM = 0
GOTO INTER-PRIVILEGE-LEVEL-INTERRUPT; (* PE = 1, VM = 0, interrupt or trap gate, nonconforming code segment, DPL < CPL *)
ELSE
(* VM = 1 *)
IF new code-segment DPL != 0
#GP(error_code(new code-segment selector, 0, EXT)); (* idt operand to error_code is 0 because selector is used *)
GOTO INTERRUPT-FROM-VIRTUAL-8086-MODE;
FI;
(* PE = 1, interrupt or trap gate, DPL < CPL, VM = 1 *)
FI;
ELSE
(* PE = 1, interrupt or trap gate, DPL >= CPL *)
IF VM = 1
#GP(error_code(new code-segment selector, 0, EXT)); (* idt operand to error_code is 0 because selector is used *)
FI;
IF new code segment is conforming or new code-segment DPL = CPL
GOTO INTRA-PRIVILEGE-LEVEL-INTERRUPT;
ELSE
(* PE = 1, interrupt or trap gate, nonconforming code segment, DPL > CPL *)
#GP(error_code(new code-segment selector, 0, EXT)); (* idt operand to error_code is 0 because selector is used *)
FI;
FI;
END;
INTER-PRIVILEGE-LEVEL-INTERRUPT: (* PE = 1, interrupt or trap gate, non-conforming code segment, DPL < CPL *)
IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *)
(* Identify stack-segment selector for new privilege level in current TSS *)
IF current TSS is 32-bit
TSSstackAddress = (new code-segment DPL << 3) + 4;
IF (TSSstackAddress + 5) > current TSS limit
#TS(error_code(current TSS selector, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
NewSS = 2 bytes loaded from (TSS base + TSSstackAddress + 4);
NewESP = 4 bytes loaded from (TSS base + TSSstackAddress);
ELSE
(* current TSS is 16-bit *)
TSSstackAddress = (new code-segment DPL << 2) + 2
IF (TSSstackAddress + 3) > current TSS limit
#TS(error_code(current TSS selector, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
NewSS = 2 bytes loaded from (TSS base + TSSstackAddress + 2);
NewESP = 2 bytes loaded from (TSS base + TSSstackAddress);
FI;
IF NewSS is NULL
#TS(EXT);
FI;
IF NewSS index is not within its descriptor-table limits or NewSS RPL != new code-segment DPL
#TS(error_code(NewSS, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
Read new stack-segment descriptor for NewSS in GDT or LDT;
IF new stack-segment DPL != new code-segment DPL or new stack-segment Type does not indicate writable data segment
#TS(error_code(NewSS, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
IF NewSS is not present
#SS(error_code(NewSS, 0, EXT));
FI; (* idt operand to error_code is 0 because selector is used *)
ELSE
(* IA-32e mode *)
IF IDT-gate IST = 0
TSSstackAddress = (new code-segment DPL << 3) + 4;
ELSE
TSSstackAddress = (IDT gate IST << 3) + 28;
FI;
IF (TSSstackAddress + 7) > current TSS limit
#TS(error_code(current TSS selector, 0, EXT);
FI;
(* idt operand to error_code is 0 because selector is used *)
NewRSP = 8 bytes loaded from (current TSS base + TSSstackAddress);
NewSS = new code-segment DPL; (* NULL selector with RPL = new CPL *)
FI;
IF IDT gate is 32-bit
IF new stack does not have room for 24 bytes (error code pushed) or 20 bytes (no error code pushed)
#SS(error_code(NewSS, 0, EXT));
(* idt operand to error_code is 0 because selector is used *)
FI
ELSE
IF IDT gate is 16-bit
IF new stack does not have room for 12 bytes (error code pushed) or 10 bytes (no error code pushed);
#SS(error_code(NewSS, 0, EXT));
FI; (* idt operand to error_code is 0 because selector is used *)
ELSE
(* 64-bit IDT gate *)
IF StackAddress is non-canonical
#SS(EXT);
FI; (* Error code contains NULL selector *)
FI;
FI;
IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *)
IF instruction pointer from IDT gate is not within new code-segment limits
#GP(EXT);
FI; (* Error code contains NULL selector *)
ESP = NewESP;
SS = NewSS; (* Segment descriptor information also loaded *)
ELSE
(* IA-32e mode *)
IF instruction pointer from IDT gate contains a non-canonical address
#GP(EXT);
FI; (* Error code contains NULL selector *)
RSP = NewRSP & FFFFFFFFFFFFFFF0H;
SS = NewSS;
FI;
IF IDT gate is 32-bit
CS:EIP = Gate(CS:EIP); (* Segment descriptor information also loaded *)
ELSE
IF IDT gate 16-bit
CS:IP = Gate(CS:IP); (* Segment descriptor information also loaded *)
ELSE
(* 64-bit IDT gate *)
CS:RIP = Gate(CS:RIP); (* Segment descriptor information also loaded *)
FI;
FI;
IF IDT gate is 32-bit
Push(far pointer to old stack); (* Old SS and ESP, 3 words padded to 4 *)
Push(EFLAGS);
Push(far pointer to return instruction); (* Old CS and EIP, 3 words padded to 4 *)
Push(ErrorCode); (* If needed, 4 bytes *)
ELSE
IF IDT gate 16-bit
Push(far pointer to old stack); (* Old SS and SP, 2 words *)
Push(EFLAGS(15-0]);
Push(far pointer to return instruction); (* Old CS and IP, 2 words *)
Push(ErrorCode); (* If needed, 2 bytes *)
ELSE
(* 64-bit IDT gate *)
Push(far pointer to old stack); (* Old SS and SP, each an 8-byte push *)
Push(RFLAGS); (* 8-byte push *)
Push(far pointer to return instruction); (* Old CS and RIP, each an 8-byte push *)
Push(ErrorCode); (* If needed, 8-bytes *)
FI;
FI;
CPL = new code-segment DPL;
CS(RPL) = CPL;
IF IDT gate is interrupt gate
IF = 0 (* Interrupt flag set to 0, interrupts disabled *);
FI;
TF = 0;
VM = 0;
RF = 0;
NT = 0;
END;
INTERRUPT-FROM-VIRTUAL-8086-MODE: (* Identify stack-segment selector for privilege level 0 in current TSS *)
IF current TSS is 32-bit
IF TSS limit < 9
#TS(error_code(current TSS selector, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
NewSS = 2 bytes loaded from (current TSS base + 8);
NewESP = 4 bytes loaded from (current TSS base + 4);
ELSE
(* current TSS is 16-bit *)
IF TSS limit < 5
#TS(error_code(current TSS selector, 0, EXT));
FI; (* idt operand to error_code is 0 because selector is used *)
NewSS = 2 bytes loaded from (current TSS base + 4);
NewESP = 2 bytes loaded from (current TSS base + 2);
FI;
IF NewSS is NULL
#TS(EXT);
FI; (* Error code contains NULL selector *)
IF NewSS index is not within its descriptor table limits or NewSS RPL != 0
#TS(error_code(NewSS, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
Read new stack-segment descriptor for NewSS in GDT or LDT;
IF new stack-segment DPL != 0 or stack segment does not indicate writable data segment
#TS(error_code(NewSS, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
IF new stack segment not present
#SS(error_code(NewSS, 0, EXT));
FI; (* idt operand to error_code is 0 because selector is used *)
IF IDT gate is 32-bit
IF new stack does not have room for 40 bytes (error code pushed) or 36 bytes (no error code pushed)
#SS(error_code(NewSS, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
ELSE
(* IDT gate is 16-bit *)
IF new stack does not have room for 20 bytes (error code pushed) or 18 bytes (no error code pushed)
#SS(error_code(NewSS, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
FI;
IF instruction pointer from IDT gate is not within new code-segment limits
#GP(EXT);
FI; (* Error code contains NULL selector *)
tempEFLAGS = EFLAGS;
VM = 0;
TF = 0;
RF = 0;
NT = 0;
IF service through interrupt gate
IF = 0;
FI;
TempSS = SS;
TempESP = ESP;
SS = NewSS;
ESP = NewESP;
(* Following pushes are 16 bits for 16-bit IDT gates and 32 bits for 32-bit IDT gates;Segment selector pushes in 32-bit mode are padded to two words *)
Push(GS);
Push(FS);
Push(DS);
Push(ES);
Push(TempSS);
Push(TempESP);
Push(TempEFlags);
Push(CS);
Push(EIP);
GS = 0; (* Segment registers made NULL, invalid for use in protected mode *)
FS = 0;
DS = 0;
ES = 0;
CS:IP = Gate(CS); (* Segment descriptor information also loaded *)
IF OperandSize = 32
EIP = Gate(instruction pointer);
ELSE
(* OperandSize is 16 *)
EIP = Gate(instruction pointer) AND 0000FFFFH;
FI;
(* Start execution of new routine in Protected Mode *)
END;
INTRA-PRIVILEGE-LEVEL-INTERRUPT:
(* PE = 1, DPL = CPL or conforming segment *)
IF IA32_EFER.LMA = 1 (* IA-32e mode *)
IF IDT-descriptor IST != 0
TSSstackAddress = (IDT-descriptor IST << 3) + 28;
IF (TSSstackAddress + 7) > TSS limit
#TS(error_code(current TSS selector, 0, EXT));
FI;
(* idt operand to error_code is 0 because selector is used *)
NewRSP = 8 bytes loaded from (current TSS base + TSSstackAddress);
FI;
IF 32-bit gate (* implies IA32_EFER.LMA = 0 *)
IF current stack does not have room for 16 bytes (error code pushed) or 12 bytes (no error code pushed)
#SS(EXT);
FI; (* Error code contains NULL selector *)
ELSE
IF 16-bit gate (* implies IA32_EFER.LMA = 0 *)
IF current stack does not have room for 8 bytes (error code pushed) or 6 bytes (no error code pushed)
#SS(EXT);
FI; (* Error code contains NULL selector *)
ELSE
(* IA32_EFER.LMA = 1, 64-bit gate *)
IF NewRSP contains a non-canonical address
#SS(EXT); (* Error code contains NULL selector *)
FI;
FI;
FI;
FI;
IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *)
IF instruction pointer from IDT gate is not within new code-segment limit
#GP(EXT);
FI; (* Error code contains NULL selector *)
ELSE
IF instruction pointer from IDT gate contains a non-canonical address
#GP(EXT);
FI; (* Error code contains NULL selector *)
RSP = NewRSP & FFFFFFFFFFFFFFF0H;
FI;
IF IDT gate is 32-bit (* implies IA32_EFER.LMA = 0 *)
Push (EFLAGS);
Push (far pointer to return instruction); (* 3 words padded to 4 *)
CS:EIP = Gate(CS:EIP); (* Segment descriptor information also loaded *)
Push (ErrorCode); (* If any *)
ELSE
IF IDT gate is 16-bit (* implies IA32_EFER.LMA = 0 *)
Push (FLAGS);
Push (far pointer to return location); (* 2 words *)
CS:IP = Gate(CS:IP); (* Segment descriptor information also loaded *)
Push (ErrorCode); (* If any *)
ELSE
(* IA32_EFER.LMA = 1, 64-bit gate *)
Push(far pointer to old stack); (* Old SS and SP, each an 8-byte push *)
Push(RFLAGS); (* 8-byte push *)
Push(far pointer to return instruction); (* Old CS and RIP, each an 8-byte push *)
Push(ErrorCode); (* If needed, 8 bytes *)
CS:RIP = GATE(CS:RIP);
(* Segment descriptor information also loaded *)
FI;
FI;
CS(RPL) = CPL;
IF IDT gate is interrupt gate
IF = 0;
FI;
(* Interrupt flag set to 0;interrupts disabled *)
TF = 0;
NT = 0;
VM = 0;
RF = 0;
END;
왜 SS는 4 바이트를 소모한다는 것이다? 세그먼트 선택기가 2 바이트를 사용하는 것으로 알고 있습니다. 내가 뭘 놓치고 있니? – gztomas
@gztomas 정렬. 2 개의 추가 바이트는 필러이므로 스택이 4의 배수로 정렬되도록 유지합니다. – hirschhornsalz
스택 전환이 발생하면 스택에 'SS'/ 'ESP'가 저장됩니다. 이것은 (커널/링 0에 이미있는 동안 인터럽트 이벤트에 대한) 인터 특권 이벤트 (usermode/ring 3에있는 동안 인터럽트)와 기본 권한이 아닐 때 내부적 인 권한조차도 _force 할 수 있습니다. IDT에서 _task gate_. 이것은 일반적이지는 않습니다 (이중 장애에 대해서는 솔라리스 32 비트/x86입니다,'# DF'). "좋은 스택"을 보장하는 합리적인 방법이기 때문에, 값을 포함한 모든 레지스터 상태를 유지할 수 있습니다. "나쁜 스택 포인터"의). –