1. 스택 영역을 사용한 태스크 스위칭

(1) 인터럽트를 위한 스택

1) 인터럽트가 시작되었을 ,  커널 스택 영역은 다음과 같이 데이터를 쌓습니다.

 

SS0

 

 

ESP0

 

SS

ESP

 

EFLAGS

 

 

CS

 

EIP

 

 

2) 유저 데이터 세그먼트 셀렉터 값을 스택에 저장

DS, ES, FS, GS 유저 데이터 세그먼트 셀렉터 값이 존재하여, 값을 커널 데이터 세그먼트 셀렉터 값으로 바꾸어야 인터럽트 핸들러에서 데이터를 사용할 있습니다. 유저 데이터 세그먼트 셀렉터 값을 스택에 저장 한후, 커널 데이터 세그먼트 셀렉터 값으로 바꾸어 줍니다.

 

SS0

 

 

ESP0

 

SS

ESP

 

EFLAGS

 

 

CS

 

EIP

 

 

GS

 

 

FS

 

 

ES

 

 

DS

ESP

 

 

 

 

 

 

 

3) PIC 초기화

4) 인터럽트 루틴 수행

여기서는 .This is the timer interrupt 라는 문자열을 표시하고, 첫번째 문자의 값을 1 증가 시킵니다.

여기 까지의 스택 모습은 다음과 같습니다

 

SS0

 

 

ESP0

 

SS

ESP

 

EFLAGS

 

 

CS

 

EIP

 

 

GS

 

 

FS

 

 

ES

 

 

DS

 

EAX

EBX

 

ECX

 

EDX

 

EBX

 

EBP

 

ESI

 

EDI

ESP

 

 

5) 인터럽트를 마치고 ret_from_int 함수로

Ret_from_int 함수에서는 인터럽트 핸들러가 유저 영역 실행 중에 발생 했는지 커널 영역 실행 중에 발생 했는지 알아보는 루틴으로 되어 있습니다.

                  mov eax, [esp+52]

                  and eax, 0x00000003

ESP+52 (ESP+4*13) 인터럽트 실행 전의 CS 값을 참조합니다. 값에 and 3 하면 CS RPL 값을 있습니다.

                  mov bx, cs

                  and ebx, 0x00000003

                  cmp eax, ebx

마찬가지로 인터럽트 핸들러가 실행하고 뒤의 CS 값의 RPL 구합니다.

값을 구하여 비교하고, 만약 스택에서 뽑아낸 CS 값이 크다면 이전에 실행되던 태스크는 유저모드 태스크 이므로 태스크 스위칭을 위한 루틴 scheduler: 점프하고작거나 같다면 커널 모드 루틴 실행 중에 인터럽트이므로 스택에 저장해 두었던 범용 레지스터, 데이터 세그먼트 셀렉터 모두를 POP하여 스택에서 꺼내고, IRET 통해 EIP, Cs, Eflag 스택에서 꺼낸다음, 인터럽트가 발생한 시점으로 돌아갑니다.

 

(2) 유저 모드 태스크를 위한 스택

유저 모드 태스크에 각각 실행하던 레지스터 값을 저장하기 위해 RAM 상에 스택을 가지고 있습니다. 스택은 커널 모드 스택이며, 유저 모드에서 실행되는 루틴은 실행되선 안됩니다.

1) 유저 프로그램을 위한 레지스터 저장 영역 예시

times 63 dd 0

User1Stack:

User1regs:

                  dd 0, 0, 0, 0, 0, 0, 0, 0

                  dw UserDataSelector, 0

                  dw UserDataSelector, 0

                  dw UserDataSelector, 0

                  dw UserDataSelector, 0

                  dd user_process1

                  dw UserCodeSelector, 0

                  dd 0x200

                  dd User1Stack

                  dw UserDataSelector, 0

 

Times 63 dd 0 유저 태스크의 스택을 만들어 주는 영역입니다. 다음과 같이 스택이 생성됩니다.

0

UserDataSelector(SS)

User1Stack(ESP)

0x200(EFLAGS)

UserCodeSelector(CS)

0

User_process1(EIP)

0

UserDataSelector(GS)

0

UserDataSelector(FS)

0

UserDataSelector(ES)

0

UserDataSelector(DS)

0(EAX)

0(EBX)

0(ECX)

0(EDX)

0(EBX)

0(EBP)

0(ESI)

0(EDI)

 

라벨이 아래쪽에 지정되어 있는 것은 스택이여서, PUSH 될때 메모리의 작은 번지수를 향하여 진행되기 때문입니다스택의 아래부분에는 범용 레지스터들이 저장되는 공간이 있으며, POPAD 명령을 사용하여 메모리의 번지수방향으로 내려가며 복구하게 됩니다.

데이터 세그먼트 셀렉터 부분은 순서대로 pop 하며 복구합니다.

위의 EIP, CS, EFLGAS, ESP, SS iret명령을 통해 한번에 CPU 복구되게 됩니다.

소스에는 초기값으로 EIP 부분에 user_process1 지정되어 있으며, 프로그램이 실행되면서 EIP 영역의 값이 계속 변할 것입니다. 영역은 태스크스위칭이 일어났을 처음으로 실행 해야하는 명령어가 저장되어 있는 부분입니다.

2) 유저 프로세스

다음 코드는 유저 프로세스의 예시입니다.

user_process1:

                  mov eax, 80*2*2+2*5

                  lea ebx, [msg_user_process1_1]

                  int 0x80

                  mov eax, 80*2*3+2*5

                  lea ebx, [msg_user_process1_2]

                  int 0x80

                  inc byte [msg_user_process1_2]

                  jmp user_process1

 

msg_user_process1_1 db "User Process1", 0

msg_user_process1_2 db ".I'm running now", 0

 

Int 0x80 IDT 0x80번째 있는 트랩 게이트를 이용하겠다는 의미입니다.

                  push eax

                  mov ax, SysDataSelector

                  mov ds, ax

                  mov es, ax

                  mov fs, ax

                  mov gs, ax

                  pop eax

 

                  mov edi, eax

                  lea esi, [ebx]

                  call printf

 

인터럽트 서비스 루틴의 코드의 일부입니다. 세그먼트 셀렉터 레지스터를 커널의 데이터 세그먼트 셀렉터로 설정하였습니다. 과정에서 eax 사용하기 때문에, 스택에 eax 옮겨놓고 작업이 끝나면 다시 꺼내서 eax 저장합니다.

 

3) 태스크 스위칭

1) 태스크 스위칭 준비

CurrentTask dd 0 ; 현재 실행 중인 태스크 번호

NumTask dd 20    ; 모든 태스크의

TaskList :

                  times 5 dd 0  ; 태스크 저장 영역의 포인터 배역

 

다음 코드는 태스크 스위칭을 위해서 정의한 변수 선언입니다. 다음의 C언어 코드와 유사합니다.

int CurrentTask = 0;

int NumTask = 20;

int TaskList[5] = {0,};

 

TaskList 유저 영역 태스크가 사용하는 레지스터 저장 영역의 포인터를 계속해서 넣어줍니다. (4byte 포인터이므로 4 더하면서 넣습니다)

                  mov eax, [CurrentTask]

                  add eax, TaskList

                  lea edx, [User1regs]

                  mov [eax], edx

                  add eax, 4

                  lea edx, [User2regs]

                  mov [eax], edx

                  add eax, 4

 

2) 태스크 스위칭

scheduler:

                  lea esi, [esp]

 

                  xor eax, eax

                  mov eax, [CurrentTask]

                  add eax, TaskList

 

                  mov edi, [eax]

 

                  mov ecx, 17

                  rep movsd

                  add esp, 68

 

현재 커널 영역에 저장된 모든 레지스터 값을 유저 모드 태스크의 스택 위에 있는 레지스터 저장 공간으로 복사를 합니다.  이를 구현하기 위해서 ESP (스택 포인터) ESI 넣고 레지스터 저장 공간의 주소 포인터를 EDI 넣은뒤 rep movsd 값을 복사합니다.

이때, 커널 스택 영역에 저장된 레지스터 값은 이제 필요가 없어, ESP+68, 스택 포인터를 옮겨 원래대로 되돌립니다. 나중에 값은 덮어 씌여져 없어질 것입니다.

 

                  add dword [CurrentTask], 4

                  mov eax, [NumTask]

                  mov ebx, [CurrentTask]

                  cmp eax, ebx

                  jne yet

                  mov byte [CurrentTask], 0

 

yet:

                  xor eax, eax

                  mov eax, [CurrentTask]

                  add eax, TaskList

                  mov ebx, [eax]

 

CurrentTask 변수는 포인터로 사용되는데, 값에 4 ,  NumTask 비교하여, 같으면 모든 태스크를 번씩 수행한 것으로 보아, CurrentTask 변수를 0으로 만들어 다시 처음부터 수행합니다. 다음 다음에 실행할 태스크의 레지스터영역의 주소를 ebx 넣어줍니다.

 

3)TSS

TSS 영역을 하나만 사용하여, 인터럽트로 커널로 진입했을 , ESP 있는 포인터로 스택을 사용합니다. TSS 영역의 ESP0 현재 ESP 값을 넣습니다.

ESP 값은 스택을 이용하여 태스크 스위칭을 하고 레지스터 값을 복원하기 위해 사용됩니다.

이와 같이 스택에 레지스터를 저장하고 복원하는 것을 반복하면서 태스크 스위칭이 이루어 집니다.

(POPAD, POP, iret 등등등)

 

3. 태스크 실행

                  mov eax, [CurrentTask]

                  add eax, TaskList

                  mov ebx, [eax]

                  jmp sched

 

CurrentTask 변수를 이용하여 레지스터 저장 영역의 포인터를 꺼내, EBX 넣고 sched 번지로 점프하여 레지스터 값을 복원하여 IRET 명령을 통해 태스크를 실행합니다.

 하여 레지스터 값을 복원하여 IRET 명령을 통해 첫 태스크를 실행합니다.

1. 유저 모드 세그먼트

다음 코드는 유저 모드 세그먼트영역을 지정하는 디스크립터입니다.

                  dd 0x0000FFFF, 0x00FCFA00

                  dd 0x0000FFFF, 0x00FCF200

 

유저 모드의 코드 세그먼트

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

0xFFFF

0x0000

1

11

1

1010

0x00

0x00

1

1

1

1

0xC

63

62

61

60

59

58

57

56

55

54

53

52

51

50

49

48

유저모드의 데이터 세그먼트

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

0xFFFF

0x0000

1

11

1

0010

0x00

0x00

1

1

1

1

0xC

63

62

61

60

59

58

57

56

55

54

53

52

51

50

49

48

 

디스크립터의 셀렉터 번호는 다음과 같이 나타냅니다.

UserCodeSelector equ 0x28+3

UserDataSelector equ 0x30+3

 

3 더하는 것은 세그먼트 셀렉터의 RPL 부분에 유저 모드를 뜻하는 권한 레벨 3 넣어주겠다는 의미입니다.

15

 

 

 

 

 

 

 

 

 

 

 

3

2

1

0

 

 

 

 

 

 

 

 

 

 

 1

0

1

0

1

1

 

15

 

 

 

 

 

 

 

 

 

 

 

3

2

1

0

 

 

 

 

 

 

 

 

 

 

 1

1

0

0

1

1

 

세그먼트 디스크립터는5, 6번째 위치에 있고, TI 모두 0이므로 GDT 존재함을 있습니다.

 

2. 콜게이트 설정

GDT 게이트 디스크립터를 만들었습니다.

descriptor7:

                  dw 0

                  dw SysCodeSelector

                  db 0x02

                  db 0xEC

                  db 0

                  db 0

 

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

0x00

SysCodeSelector (ox08)

1

11

0

1

1

0

0

 

사용안함

0x2

0x00

63

62

61

60

59

58

57

56

55

54

53

52

51

50

49

48

 

커널 루틴의 오프셋 부분이 0으로 설정되어 있고, 부분은 Protected Mode 들어오기 전에 다시 채워 넣을 것입니다. 미리 인수의 개수를 2 지정하여 인수를 2 사용합니다.

Printf 오프셋은 0x00AD 입니다. (채워질 주소 값은 0x10000+0x00AD = 0x100AD)

                  xor eax, eax

                  lea eax, [printf]

                  add eax, 0x10000

                  mov [descriptor7], ax

                  shr eax, 16

                  mov [descriptor7+6], al

                  mov [descriptor7+7], ah

 

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

0x00AD

SysCodeSelector (ox08)

1

11

0

1

1

0

0

 

사용 안함

0x2

0x0001

63

62

61

60

59

58

57

56

55

54

53

52

51

50

49

48

 

Protected 모드로 들어온 , 임의의 값을 tts_esp0 넣어, 커널이 사용할 스택으로 지정합니다. 여기서는 일단 PM_Start 주소를 지정 합니다. 스택은 거꾸로 자람으로 메모리의 주소 마이너스 방향으로 자라납니다 . PM_Start 위에는 이상 사용하지 않는 루틴이 존재하므로 사용해도 좋습니다.

                  lea esp, [PM_Start]

 

                  mov ax, TSSSelector

                  ltr ax

 

                  mov [tss_esp0], esp

                  lea eax, [PM_Start-256]

                  mov [tss_esp], eax

 

 

3. 유저 모드로의 태스크 스위칭

유저 모드의 태스크를 실행시키겠습니다. Protected Mode 들어와 TR 레지스터, TSS영역을 세팅 , 유저모드 처럼 설정하여 IRET 명령을 통해 유저 모드의 태스크를 실행시킵니다.

(1) 세그먼트 셋팅 유저 데이터 영역 세그먼트로

                  mov ax, UserDataSelector

                  mov ds, ax

                  mov es, ax

                  mov fs, ax

                  mov gs, ax

 

데이터 관련 세그먼트에 UserDataSelector 값을 넣어줍니다.

현재 ESP 레지스터에는 커널 모드의 스택의 시작 주소를 지정하는 PM_Start 저장되어 있으므로 유저 모드 스택으로 바꾸어 주기 위해 PM_Start-256 값을 지정합니다.

Lea esp, [PM_Start-256]

 

(2) 인터럽트에 걸린 처럼 스택을 채우기

인터럽트 루틴에서 유저 모드의 레지스터를 스택에 저장해놓았다가 수행을 마치고, 유저 모드로 돌아갈 다시 복귀 시킵니다. 인터럽트 루틴을 수행한 것은 아니지만, 그런 상황을 다음과 같이 재현하여, 유저 태스크를 실행시킬 것입니다.

UserDataSelector(SS)

Esp(ESP)

0x200(EPLAGS)

UserCodeSelector(CS)

User_process(EIP)

 

 

Push 명령어로 다음과 같이 스택을 꾸며줍니다.

                  push dword UserDataSelector

                  push esp

                  push dword 0x200

                  push dword UserCodeSelector

                  lea eax, [user_process]

                  push eax

                  iretd

 

IRET으로 돌아갈 유저 모드에서 사용하는 SS 복구되지만 DS, ES, Fs, GS 셀렉터들은 값이 복구 되지 않아 미리 값을 채웠습니다.

EIP user_process 함수의 주소(오프셋) 지정되어 있기 때문에 user_process 실행합니다.


4. 콜게이트를 사용한 시스템

커널 모드의 함수인 printf 실행하기 위해 게이트를 이용하여 시스템 콜을 합니다. 다음과 같이 스택이 만들어 집니다.

 

(1) 특권 레벨 3 스택 : 인자2

80*2*7

 

Parameter1

ESP

 

 

(2) 특권 레벨1 스택 :

 

SS

 

ESP

 

80*2*7

EBP+8

Parameter1

 

Cs

EBP

EIP

 

ES

ESP

EAX

 

printf:

                  mov ebp, esp

                  push es

                  push eax

                  mov ax, VideoSelector

                  mov es, ax

                  mov esi, [ebp+8]

                  mov edi, [ebp+12]

 

Printf 함수에서는 먼저 esp(tss esp0) 값을 ebp 지정을 합니다. 프로그램 진행 중에 바뀔 esp 값을 복원하기 위해 백업해 것입니다.

EBP+8 하여 첫번째 인수인 문자열을 접근 있고, 두번째 인수는 EBP+12 사용해 접근 있습니다.

CPU의 보호 레벨은 0~ 3, 4개로 실제로 쓰이는 것은 0과, 3 2개입니다. (숫자가 아닌 보안 수준이)낮은 레벨의 태스크가 높은 레벨의 데이터를 참조(3 레벨의 태스크가 0 레벨 태스크) 하면 일반 보호 에러(#GP)가 발생하게 됩니다.

1. CPU 보호 레벨

 

1) CPL(Current Priviliege level)

현재 실행되고 있는 태스크의 특권 레벨로, CS, SS 셀렉터 레지스터의 0, 1번째 비트에 있는 수 입니다. 프로그램이 다른 특권 레벨의 코드 세그먼트로 제어가 바뀌면 CPU는 CPL을 변경하게 됩니다.

 

2) DPL(Description Privilege Level)

디스크립터를 통해서 세그먼트 영역으로 접근할 때, 항상 CPL과 DPL을 비교하여 접근이 가능한지 불가능한지 판단이 이루어 지게 됩니다.

 

3) RPL(Requested Privilege Level)

콜게이트(낮은 특권 레벨에서 높은 특권 레벨의 루틴을 사용할 수 있게 하는 관문)을 통해 레벨 3인 프로세스가 특권 레벨 0에 해당하는 루틴을 실행할 때, 일시적으로 특권 레벨 0에 해당하는 데이터 영역에 접근할 수 있습니다. 이러한 현상을 사용하여 악용하는 것을 막기 위해 OS는 RPL 값을 사용합니다.

어떤 레벨의 프로세스가 루틴을 불러들였는지 기록하여, 낮은 특권 레벨이 루틴을 불렀을 때 높은 특권 레벨의 데이터 영역을 보호합니다.

 

2. 콜 게이트

콜게이트는 인터럽트, 예외와 마찬가지로 낮은 특권 레벨의 프로그램이 높은 특권 레벨로 변경되는 수단으로 사용됩니다. 하드웨어 인터럽트와 예외는 응용 프로그램과 상관 없이 특권 레벨이 변경되지만, 소프트웨어 인터럽트와 콜게이트는 낮은 특권 레벨의 프로그램에 따라 높은 특권 레벨의 루틴을 사용할 수 있습니다.

컴퓨터의 RAM, 하드디스크에 들어 있는 자료, 그리고 하드웨어 입출력 장치등은 커널에 의해서 관리되고 유저 프로그램은 커널의 루틴의 도움을 받아 이러한 자료들을 잠시 일부분 사용할 수 있습니다.

콜게이트도 GDT 테이블의 디스크립터로 처리되며, 낮은 특권 레벨의 프로그램이 높은 특권 레벨의 프로그램의 일부분을 사용하기 위한 창구입니다.

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

커널 루틴의 오프셋 15 - 0비트

핸들러의 코드 세그먼트 셀렉터

P

DPL

0

1

1

0

0

 

사용안함

인수의 개수

커널 루틴의 오프셋 31 - 16

63

62

61

60

59

58

57

56

55

54

53

52

51

50

49

48

 

이 디스크립터를 GDT에 지정하고, 유저 프로그램은 코드 셀렉터와 마찬가지로 디스크립터를 셀렉터로 선택하여 JMP나 CALL 명열을 내릴 수 있습니다.

 

3. 코드와 데이터의 특권 레벨 관계

CALL 명령어는 낮은 특권 레벨에서 높은 특권 레벨로, RET 명령은 높은 특권 레벨에서 낮은 특권 레벨로 이동하는 명령어 이기 때문에 이 명령어를 사용합니다. JMP 는 특권 레벨 간의 이동이 불가능 하며 JMP를 이용하여 특권 레벨의 이동을 사용해야 한다면 콜게이트 사용하여야 합니다.

 

(1) CALL 과 RET의 특권 레벨 변화

Q : CALL 명령어로 특권 레벨 0의 루틴을 불러 낼 때

A : CS 셀렉터의 0, 1 비트에 00이 들어가고 CPL은 0이 됩니다.

Q : RET 명령어로 다시 특권 레벨 3으로 돌아갈 때

A : CS 셀렉터의 0, 1비트에 11이 들어가고 CPL은 1이 됩니다.

 

코드 세그먼트 영역의 특권 레벨 DPL과 CPL은 어떤 상황에서 든 기본적으로 값이 같습니다.

예외 >> Conforming 세그먼트

특권 레벨 0의 루틴을 불러내도 CPL의 값은 그대로 3인 채 실행되었다 IRET으로 돌아옵니다. (Call gate와 관련)

 

(2) 특권 레벨과 접근 권한

특권 레벨 0에서는 모든 특권 레벨의 데이터 세그먼트 영역에 접근이 가능하지만 낮은 특권 레벨의 프로세스에서는 높은 특권 레벨의 데이터에 접근이 금지됩니다.

 

4. 특권 레벨 변동 시의 스택의 변화

 

스택 스위칭은 높은 특권 레벨의 루틴이 스택 공간의 부족 때문에 크래시 되지 않게 하기 위해서, 그리고 낮은 특권 레벨의 루틴이 스택을 통해 높은 특권 레벨의 루틴에 간섭하지 못하게 하기 위해 사용 됩니다.

핸들러나 커널 루틴으로 들어가기 전에 스택에 돌아올 주소 등을 넣어 두었다가 핸들러나 커널 루틴이 끝나고 다시 유저 모드 태스크로 돌아오기 위해 스택에 넣어 두었던 값들을 사용합니다.

 

(1) CALL 명령 – 유저 태스크 가 콜 게이트를 이용하여 커널 모드의 루틴

1) 호출 구문에 인수가 없는 경우

이 태스크 TSS 영역의 SS0, ESP0의 값을 참조하여 커널 모드의 스택에 현재 유저 태스크가 사용하고 있는 SS, ESP, 그리고 유저 태스크가 현재 진행중인 루틴의 주소, CS, EIP를 PUSH ( 스택방향 )

SS

 

ESP

CS

 

EIP

 

콜게이트에 지정된 커널 모드의 루틴 주소로 점프하고 실행

루틴을 마치고 RET 명령을 실행하여 커널 모드의 스택에 저장된 SS, ESP, CS, EIP를 POP(CS 를 먼저 검사한 후, 현재 커널 모드 보다 낮은 특권 레벨이면(콜게이트를 통한 특권레벨 이동일 경우???) SS와 ESP를 POP 합니다.)

2) 호출 구문에 인수가 있는 경우

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

커널 루틴의 오프셋 15 - 0비트

핸들러의 코드 세그먼트 셀렉터

P

DPL

0

1

1

0

0

 

사용안함

인수의 개수

커널 루틴의 오프셋 31 - 16

63

62

61

60

59

58

57

56

55

54

53

52

51

50

49

48

 

콜게이트를 통한 커널 루틴에서 사용할 인수의 개수를 미리 기입함

유저 레벨의 SS, ESP의 주소에 인수들을 PUSH 하고 콜게이트를 통하여 커널 레벨(특권 레벨 0) 루틴으로 들어가도 커널 레벨의 루틴에서는 스택 주소가 SS0, ESP0로 변경되어 pop 하여도 관련 없는 값을 참조하게 될 것입니다.

 

GDT 디스크립터의 인수의 개수 항목에 2가 들어있다면 유저 레벨의 스택에서 2개를 커널 모드의 스택에 복사합니다.

(스택의 방향은 원래 위에서 아래로 자라지만 여기서는 작성자의 착각으로;;; 반대로 표시했습니다. 반대로 뒤집으시면 거꿀로 자라는 스택이 됩니다)

Param1

스택 진행 방향

 

Param2

 

ESP

 

←SS

 
  

 

Param1과 Param2를 복사합니다.

 

SS

 

스택 진행 방향

ESP

Param1

Param2

 

CS

  
 

EIP

 

ESP0

 

←SS0

 
  

 

(2) 인터럽트 예외가 발생하였을 때의 스택

EFLAGS가 추가된 것을 제외하면 콜 게이트와 흡사합니다

1) 커널 모드에서 인터럽트가 걸렸을 때

특권 레벨 0에서 진행 되므로 SS, ESP 그대로 값을 사용하고, 스택에 EFLAGS, CS, EIP를 PUSH 합니다.

 

EFLAGS

↑스택 진행 방향

 

CS

  
 

EIP

 

ESP

 

←SS

 
  

 

2) 유저 레벨 에서 인터럽트가 발생했을 때

유저 레벨 태스크의 TSS 영역에서 SS0, ESP0를 CPU의 SS, ESP 레지스터에 복사하여, 콜게이트 경우에는 유저 모드의 태스크가 사용하던 SS, ESP, CS, EIP등의 레지스터의 값을 PUSH하여 저장합니다. IRET으로 유저 모드로 돌아갈때는 스택에 있는 값을 POP하여 CPU의 각각의 레지스터에 복원합니다.

 

스택 진행 방향

 
 
 
  
 
  

ESP

 

←SS

 
  

 

SS

 

스택 진행 방향

ESP

EFLAGS

 

CS

  
 

EIP

 

ESP0

 

←SS0

 
  

+ Recent posts