[Memory Management : Translating Logical Address to Linear Address 2]
Embedded Lab/linux, x86 2012. 10. 8. 03:02이번시간의 목표는 프로그램에서 사용하는 논리 주소 (Logical Address) 를 선형 주소 (Linear Address) 로 변경 함으로써 세그먼테이션 과정이 어떻게 일어나는지 확인 하는 것이다. 세그먼테이션에 대해서는 지난번 글을 확인 하도록 하자.
Memory Management : Segmentation 1
Memory Management : Segmentation 2Memory Management : Translating Logical Address to Linear Address 1
인텔 X86 아키텍처에서 논리 주소가 물리 주소로 변경되는 과정은 다음과 같이 요약할 수 있다.
논리주소 -> 세그먼테이션 -> 선형주소 -> 페이징 -> 물리주소
자, 이제부터 시작 해 보자. 어느 논리 주소를 선형 주소로 변경 할 것인가?
이전 포스트에서 언급했던 PsGetCurrentThread 함수가 위치한 논리 주소를 선형 주소로 변경 해 보자. WinDBG 에서 확인해보면 PsGetCurrentThread 함수는 0x8052993c 에 위치한다.
kd> x nt!PsGetCurrentThread
8052993c nt!PsGetCurrentThread = <no type information>
kd> u 8052993c
nt!PsGetCurrentThread:
8052993c 64a124010000 mov eax,dword ptr fs:[00000124h]
80529942 c3 ret
kd> db 8052993c
8052993c 64 a1 24 01 00 00 c3 cc-cc cc cc cc 64 a1 24 01 d.$.........d.$.
8052994c 00 00 8b 80 68 01 00 00-c3 cc cc cc cc cc 64 a1 ....h.........d.
첫 한바이트의 값은 0x64 다. 이 함수에 접근하기 위해서 커널에서 사용하는 셀렉터는 0x08 이다.
이것을 셀렉터 포맷에 맞추어 분석 해 보면
kd> .formats 0x08
Evaluate e-pression:
Hex: 00000008
Decimal: 8
Octal: 00000000010
Binary: 00000000 00000000 00000000 00001000
Chars: ....
Time: Thu Jan 01 09:00:08 1970
Float: low 1.12104e-044 high 0
Double: 3.95253e-323TI
Flag = 0, RPL = 0 이고, GDT 에서 1번째 ( GDT의 디스크립터는 0번째부터 시작한다. ) 디스크립터를 사용한다는걸 알 수 있다.WinDBG를 통해서 GDT의 위치를 확인 해 보자.
kd> r gdtrgdtr=8003f000
GDT 를 8바이트 (디스크립터)의 사이즈 만큼씩 잘라서 내용을 보면 아래와 같다.
kd> dq 8003f000
8003f000 00000000`00000000 00cf9b00`0000ffff
8003f010 00cf9300`0000ffff 00cffb00`0000ffff
8003f020 00cff300`0000ffff 80008b04`200020ab
8003f030 ffc093df`f0000001 0040f300`00000fff
8003f040 0000f200`0400ffff 00000000`00000000
8003f050 80008954`c0000068 80008954`c0680068
8003f060 00009302`2f40ffff 0000920b`80003fff
8003f070 ff0092ff`700003ff 80009a40`0000ffff
첫번째는 00000000`00000000 으로 채워진 널 디스크립터고, 두번째가 바로 CS가 사용하고 있는 인덱스가 1인 세그먼트 디스크립터다커널에서 사용하는 GDT 디스크립터 구조체 타입으로 변경해서 확인 해 보자.
kd> dt _KGDTENTRY -r 8003f008
nt!_KGDTENTRY
+0x000 LimitLow : 0xffff
+0x002 BaseLow : 0
+0x004 HighWord : __unnamed
+0x000 Bytes : __unnamed
+0x000 BaseMid : 0 ''
+0x001 Flags1 : 0x9b ''
+0x002 Flags2 : 0xcf ''
+0x003 BaseHi : 0 ''
+0x000 Bits : __unnamed
+0x000 BaseMid : 0y00000000 (0)
+0x000 Type : 0y11011 (0x1b)
+0x000 Dpl : 0y00
+0x000 Pres : 0y1
+0x000 LimitHi : 0y1111
+0x000 Sys : 0y0
+0x000 Reserved_0 : 0y0
+0x000 Default_Big : 0y1
+0x000 Granularity : 0y1
+0x000 BaseHi : 0y00000000 (0)
요약해보면 Base Address 는 0이고, G Flag = 1에 Limit Field 가 0xFFFFF 이므로, Table Limit 은 0xFFFFFFFF 다. CS 가 사용하고 있는 세그먼트는 0x00000000 ~ 0xFFFFFFFF 이므로 선형 주소를 구하기 위해서는 현재 논리 주소에다가 Base Address 인 0을 더하면 선형주소가 나온다. 따라서 우리가 원했던 0x8052993c 의 선형주소는 0x8052993c 이다.
윈도우즈에서 사용하는 코드와 데이터 세그먼트의 베이스 어드레스는 0x00000000 이다. 아래를 확인 해 보자. WinDBG 에서 dg 명령어를 이용해 커널에서 사용하는 세그먼트 셀렉터들을 나열해 본것이다.
kd> dg 0 255
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0000 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
0008 00000000 ffffffff Code RE Ac 0 Bg Pg P Nl 00000c9b (커널 코드)
0010 00000000 ffffffff Data RW Ac 0 Bg Pg P Nl 00000c93 (커널 스택 세그먼트)
0018 00000000 ffffffff Code RE Ac 3 Bg Pg P Nl 00000cfb (유저 코드)
0020 00000000 ffffffff Data RW Ac 3 Bg Pg P Nl 00000cf3 (유저 - 커널 데이터 , 유저 스택 세그먼트 )
0028 80042000 000020ab TSS32 Busy 0 Nb By P Nl 0000008b
0030 ffdff000 00001fff Data RW Ac 0 Bg Pg P Nl 00000c93
0038 00000000 00000fff Data RW Ac 3 Bg By P Nl 000004f3
0040 00000400 0000ffff Data RW 3 Nb By P Nl 000000f2
0048 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
0050 8054c000 00000068 TSS32 Avl 0 Nb By P Nl 00000089
0058 8054c068 00000068 TSS32 Avl 0 Nb By P Nl 00000089
0060 00022f40 0000ffff Data RW Ac 0 Nb By P Nl 00000093
0068 000b8000 00003fff Data RW 0 Nb By P Nl 00000092
0070 ffff7000 000003ff Data RW 0 Nb By P Nl 00000092
0078 80400000 0000ffff Code RE 0 Nb By P Nl 0000009a
0080 80400000 0000ffff Data RW 0 Nb By P Nl 00000092
0088 00000000 00000000 Data RW 0 Nb By P Nl 00000092
0090 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
0098 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00A0 821b23f8 00000068 TSS32 Avl 0 Nb By P Nl 00000089
00A8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00B0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00B8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00C0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00C8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00D0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00D8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00E0 f86fa000 0000ffff Code RE Ac 0 Nb By P Nl 0000009f
00E8 00000000 0000ffff Data RW 0 Nb By P Nl 00000092
00F0 804fc698 000003b7 Code EO 0 Nb By P Nl 00000098
00F8 00000000 0000ffff Data RW 0 Nb By P Nl 00000092
0100 f8397400 0000ffff Data RW Ac 0 Bg By P Nl 00000493
0108 f8397400 0000ffff Data RW Ac 0 Bg By P Nl 00000493
0110 f8397400 0000ffff Data RW Ac 0 Bg By P Nl 00000493
윈도우즈에서 코드와 데이터 세그먼트의 베이스 어드레스가 0이므로 선형주소 = 논리 주소 공식이 성립한다.
다음시간에는 이렇게 변환한 선형주소가 어떻게 페이징되어 물리 주소로 변경되는지에 대해서 알아 보겠다.
'Embedded Lab > linux, x86' 카테고리의 다른 글
[디스크 공간 할당 방법] (0) | 2012.10.14 |
---|---|
[Memory Management : Translating Logical Address to Linear Address 1] (0) | 2012.10.08 |
[Memory Management : Segmentation 2] (0) | 2012.10.08 |
[Memory Management : Segmentation 1] (0) | 2012.10.08 |
[리눅스 커널 소스 다운로드] (0) | 2012.10.07 |