2011년 10월 18일 화요일

p5) 리눅스 정리 프로젝트 2

리버싱이 주이다. 보니 네트워크 관련해서 쭉 쓰려고 했는데요.
사실 다음이 소켓 프로그래밍이었죠. 초급 강좌를 쓰면서 리눅스를 배워 보려고 하시는 분들에게
무거운 내용이 아닐까 하여 다시 리눅스 이야기로 돌아 왔습니다. 사실 소켓 프로그램 하나 올려놓고
이러이러 하다고 이야기하는건 C 공부 밖에 안되서리 ^^;;

제가 앞에서 설명해 드린 여러 부분들은 리눅스를 전체적으로 봤을 때 별 다를게 없다는 것입니다.
담배피는 사람이야 그게 디스든 에세든 켄트등... 중요하지가 않죠. 뭐, 물론 이것저것 다 펴보았을 때의
이야기 입니다. 사족으로 한마디 하자면 담배는 하나만 계속 피는게 좋아요. 여러가지 펴 보니 원래의
맛을 잃고 다 그 담배가 그 담배 같아 보입니다. 맛을 잃는거죠 ㅠㅠ. 그래서 저도 리눅스 윈도우 다 써보는
것은 좋은데 리눅스가 아쉬운 것이 공부하기는 좋은데 너무나도 내용이 많다는 것입니다.
윈도우는 드라이버단만 좀 해도 잘한다는 소릴 듣는데 리눅스는 고수가 너무 많음...

잡소리는 그만하고 시작하겠습니다. 온라인 교재를 하나 도입했는데요.


Understanding the Linux Kernel
Understandig the LINUX KERNEL by Daniel P. Bovert & Marco Cesati의 책 내용인데요. 유명한 책인데 지금은 접속되지 않는 블로그에서 퍼놨던 거예요. 사실 외서든 번역본 이든 다 딱딱해서 내용 알기가 쉽지가 않죠. 옆길로 너무 새는 것 같아. 그냥 갈께요.

-> 메모리 어드레싱 부분 갑니다. 여러분들 램 사서 컴퓨터에 꽂죠? 리버싱 할 때 PE 파일에서 읽어오면 PC(프로그램카운터)라는 곳이 그 위치를 기억하고 IR(인스트럭트 레지스터)를 거쳐서 ALU(시퓨 코어죵)에 가면 거기서 처리한 연산 결과가 레지스터나 메모리 내용을 변화 시킵니다. 뭐, 플래그들도요. CPU와 메모리는 상당히 중요한 녀석인데 운영체제가 고 녀석들을 관리해줘요. 올리 디버거도 운영체제가 관리하는 메모리 영역(운영체제가 나눈 메모리 영역)을 이용하는 프로그램인거죠.


-> 일단 저장하고 수정해야지... 날아갈라....


Chapter 2. Memory Addressing


차례

Introduction

Memory Address
Segmentation in Hardware
->이 세그먼트란 녀석은 자주 나옵니다. 근래에는 별로 신경을 안 써도 되지만 그래도 어떤 녀석인지는 알아야 겠죠?
8bit, 16bit 시절 메모리 주소 지정이 어려울 때 나온 녀석입니다. 가령 서울에 사는 사람이 편지를 쓸 때 압구정동만 써도
서울이란 걸 다른 사람들은 알수가 있죠? 적절한 비유는 아니지만 그 서울에 해당하는 녀석이 세그먼트란 것입니다.
어떤 기준점이라고만 생각하시면 되요. -생각해보니 정말 적절한 비유는 아니지만 기준점임은 확실합니다.

Segmentation in Linux
Paging in Hardware

-> 페이징이란 녀석도 자주 나오는데 얘는 말 그대로 책에서 페이지 입니다. 메모리를 나누는 단위죠.

Paging in Linux


Introduction

물리적으로 연결되어 있는 메모리에 번지지정을 하는 일반적인 IA(Intel Architecture)의 하드웨어구조와 이를 운영체제에서 사용하는 방법을 살펴본다.

즉, segment와 paging이 적용된 system에서 logical address -> linear address -> physicall address의 변환과정을 살펴본다.


-> 실재적으로 저희가 쓰는 메모리는 physical 메모리 입니다.(교재에 오타가 있네여) 말 그대로 물리 메모리죠. 리니어 라는 건 일자 메모리라는 건데요. 저희가 쓰는 스택이라고 부르는 녀석도 실재적으로는 리니어 메모리 안의 한 부분입니다. 여러분들이 램은 2개를 꽂던 4개를 꼳던 리니어 어드레스 에서는 하나의 메모리로 인식을 한다는 것이죠. 그 하나의 메모리로 보는건 메인보드 단에서 일어나는 현상이구요. 운영체제가 그 리니어한 메모리를 힙, 스택 등 로지컬한 메모리로 변환시킵니다.


Memory Address

일반적인 IA에서 사용하는 3가지 address의 정의
-> IA는 인텔 명령어를 쓰는 녀석이라고 생각하시면 되요.
Logical adderss penrand와 instruction을 정의하는 machine language instructions.

16-bit segment selector와 32-bit offset으로 구성.

-> 세그먼트에서 또 얼마나 떨어졌는지 보는게 오프셋입니다.

Linear address

232bit로 표현되는 4GB까지 지정할수 있는 번지.
-> 32비트라 4GB까지 밖에 못써요. 32비트면 0이나 1이 32개 까지 있을 수 있는데
0 ~ 11111111111111111111111111111111 32개 이게 최대 숫자죠.

16진수로 표현하면
0x00000000 - 0xffffffff

그런데 세그먼트는 왜 있느냐? 세그먼트는 단순히 10을 곱한 겁니다.
가령 세그먼트가 1이면 오프셋으로 10으로 보시면 되구요.
세그먼트가 10이면 오프셋 100으로 보시면 됩니다.
그럼 세그먼트 오프셋 방식에서
0001:0001 하면
실재적으로는 11번지가 되는거죠. 적은 숫자로 많은 메모리 단위를 표현할 수 있기
때문에 세그먼트 오프셋이 나온겁니다. 64비트로 가고 있는 근래엔 필요없는 개념이죠.



Physical address -> 그냥 꽂은 메모리 애들 자체를 말합니다.실제 메모리칩에 포함된 메머리 cell을 지정하기 위해 사용되는 번지.

Ref)figure 2-1 Logical address translation(36p)

Ref)Intel Architecture Software Developer's Manual Volume 3

IA 4가지 동작 모드
-> 이건 CPU에 지정되어 있는 모드에요. 사실 어셈블리에서 말하는 기계어 라는 것은

CPU가 가지고 있는 명령set 입니다. 그럼 CPU마다 명령어가 다른가요?
네 그렇습니다. CPU마다 명령어가 다릅니다. 그런데 어떻게 운영체제를 깔 수 있냐고요?
당연히 운영체제에서는 해당 CPU에 패치를 하기 때문이죠. 패치란 건 해당 운영체제의
명령어들이 다 들어 가는 거예용.

Protected mode

Real-address mode

System mangement mode

Virtual-8086 mode

다음의 모든 내용은 protected mode에서의 동작을 설명한다.

Segmentation in Hardware

Segmentation provides a mechanism of isolating individual code, data, and stack modules so that multiple programs(or tasks) can run on the same processor without interfering with one another.

먼저 시스템에 reset이나 power on을 하면 real-address mode로 동작을 하고 bootstraping 과정을 거친후 protected mode로 진입한다.

Segmentation registers

logical address의 구성은 다음과 같다.

logical address = identifier or segment selector(16-bit) + offset(32bit)

segmentatiin register는 필요한 segment를 빠르게 검색하기 위해 segment selector와cs(code segment register), ss(stack segment register), ds(data segnebt register), es, fs, gs(additional data segment or gernerl purpose register)가 있고 cs register는 cpu의 Current Privilege Level(CPL)를 규정하는 2-bit를 포함하고 있다.

-> 뭐, 여기까지 질문있으시면 댓글을 이용해 주세요. 별로 설명할 내용이 없네요.
CPU는 몇가지 모드를 가지고 있고 FLAG 세팅으로 그 모드들을 바꿀 수 있습니다.
보호모드로 안 바꾸면 DOS 시절처럼 한 프로그램이 다른 프로그램의 메모리를 넘어갈 수 있습니다.
그럼 Flag만 바꾸면 무적이 되지 않느냐? 당근 운영체제가 막고 있죠 ^^ 하지만 운영체제가 다른 프로그램을 침범해도 되게 해놓은 것이! 윈도우에서는 DLL injection이고, 리눅스에서는 디바이스 드라이버죠(디바이스 드라이버를 쓰게 되면 커널모드에서 동작할 수 있습니다)

리눅스에서는 0:User-Mode 3:Kernel-Mode를 사용한다.

Segment Descriptor

Segment descriptor는 processor에게 size, segment의 위치, access control,status 를 제공하는 GDT(Global Descriptor Table)나 LDT(Local Descriptor Table)에 있는 data structure.

GDT와 LDT의 address는 gdtr,ltdr register에 저장되어있다.

Segment Descriptor의 구성 (8-byte)

Base field(32-bit): linear address이내의 segment의 0-byte의 위치.

G flag : segment limit filed를 scaling.

Limit field(20-bit): segment의 size. G flag에 영향을 받음.

G=0 -> 1byte ~ 4MB

G=1 -> 4KB ~ 4GB

S flag: segment가 system segment 인지 code,data segment인지를 표시.

Type field(4bit): 접근권한과 segment type의 여러가지 서로다른 특성을 규정.(CS, DS, TSS, LDTD, Call-gate, Trap-gate, Interrupt-gate..등등에 따라 서로 다른 특성을 규정.

DPL(2-bit):Descripor privilege level. segment에 접근할수 있는 권한을 표시.(CPL level에 의해서 접근권한이 주어진다.)

P flag: segment가 메모리에 있는지 없는지를 표시.

D/B flag: code,data segment에 따라 segment offset을 16-bit or 32-bit로 사용하는지를 표시.

AVL: OS에 따라 임의로 사용 (linux 무시)

Segment Selectors

Segment Selector의 구성(16-bit)

Index(3:15):GDT나 LDT의 8K의 entry중 하나를 지정.

TI flag:GDT나 LDT중 어느 table을 사용하는지를 정의.

RPL(Requestor Privileage level)(2-bit):selector의 level을 정의 (CPL,DPL과 관계있음).

GDT의 첫번째 entry는 항상 0으로 set (null segment selector)

GDT의 최대 entry는 (2^13)-1=8191

Segmentaion Unit

segment selector의 T1 조사 (GDT or LDT를 선택)

segment selector의 INDEX를 추출 gdtr or ldtr의 address를 합쳐 segment descriptor의 address를 결정.

segment descriptor의 BASE field와 logical adress의 offset을 합쳐 linear address를 얻는다.

Ref)figure 2-4. translating a logical address

Segmentation in Linux

리눅스에서는 아주 제한적인 segment를 사용하고 paging 사용을 더 선호한다.즉 protected flat model을 사용한다.사실 IA에는 segment 기능을 disable 할수가 없다.

paging을 선호하는 이유:

모든 processes가 같은 linear address를 이용할때 같은 segment register를 이용하기 때문에 메로리 관리가 쉬워진다.

segment의 극히 작기 때문에 모든 segment descriptor는 GDT만을 사용한다.

arch/i386/kerel/head.S 다음과 같이 정의되어 있다.


ENTRY(gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x0000000000000000 /* not used */ .quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */ .quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */ .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */ .quad 0x0000000000000000 /* not used */ .quad 0x0000000000000000 /* not used */
Paging in Hardware

Paging provides a mechanism for implementing a conventional demand-paged, virtual-memory system where section of a program's execution environment are maped into physical memory as need.

page table : linear address를 physical adress로 맴핑한 data structure.

Paging에 사용되는 flags

cr0 register의 PG flag : 0 -> linear address=physical address, 1 -> paging enable.

cr4 register의 PSE (page size extension)flag : large page size(2Mbyte,4Mbyte)

cr4 register의 PAE (physical address extention)flag: 36-bit의 physical size address가능하게 한다.

Regular Paging

4kB의 page을 갖는 방법.

구성 directory (10-bit) + table(10-bit) + offset(12-bit)

page-directory entry

page-table entry

Ref) Figure 3-14

Extended paging

4MB의 page를 갖는 방법

Three-level paginag

64-bit system에서 사용.

리눅스 ststem에서도 사용.

Hardware cache

locality principle을 이용한 hardware cache.

TLB (translation Lookaside Buffers)

linear address 변환을 빠르게 하기 위해 한번 변환된 physical address를 저장.

Paging in Linux

리눅스는 기본적으로 Three-level paging을 사용한다.

Global_dir + Middle_dir + Table + Offset 구성된다.

하지만 IA 시스템에서는 Middle dir을 사용하지 않는다.

Middle dir의 entry에 1을 넣으므로써 Global Dir과 Middle_dir을 Mapping 시킨다.

The Linear Address Fields

Page Table Handling

Reserved Page Frames

Kernel's code and data structure는 reserved page frames에 저장된다

일반적으로 Linux kernel은 물리주소 0x0010_0000부터 RAM상에 저장된다. 1MB이하 영역은 PC architecture상 BIOS에서 사용되기 때문.

Process Page Tables

linear address space는 다음 2부분으로 나뉜다.

0x0000_0000 ~ PAGE_OFFSET -1 process가 User Mode or Kernel Mode에 있을 때 사용된다.

PAGE_OFFSET ~ 0xffff_ffff process가 Kernel Mode에 있을 때 사용된다.

일반적으로 PAGE_OFFSET은 0xc000_0000(3GB)

Kernel Page Tables

다음은 kernel 자신의 page talbes을 초기화 하는 방밥에 대해 알아 본다.

Provisional kernel page tables

real mode와 protected mode 둘다 쉽게 번지 지정을 하기 위해 4MB의 paging을 한다.

Kernel은linear address 0x0000_0000 ~ 0x003f_ffff 와 PAGE_OFFSET ~ PAGE_OFFSET+0x3f_ffff둘다 physicall address 0x0000_0000 ~ 0x003f_ffff에 mapping 한다.

startup_32() assembly function에 의해 paging unit이 enable된다.

Final kernel page table

paging_init()실행.

처음 4MB의 linear와 physicall의 mapping을 제거.

User Mode process는 이 4MB의 linear address 공간을 사용할수 있게 된다.

PAGE_OFFSET상위 linear address는 User/Supervisor flag 값이 0가 되므로 User mode process가 Kernel address space접근을 거부


-> 뒤의 내용들은 그냥 한번 읽고만 가야 하는 내용들이네요. 사실 다 까먹거든요. 하지만 한번 읽어두는 것은 중요합니다. 왜냐면 한번은 읽어놔야 나중에 찾을 수가 있거든요. 사실 출근전이라 급하게 적은 감이 없잖아 있습니다만. 그 동안 뭐가 뭔지 긴가 민가 하시는 분들에게 나름 어줍잖은 지식에 대한 혼자만의 결단으로 이해를 도운 부분이 있을 것 같습니다.

댓글 없음:

댓글 쓰기

국정원의 댓글 공작을 지탄합니다.

UPBIT is a South Korean company, and people died of suicide cause of coin investment.

 UPBIT is a South Korean company, and people died of suicide cause of coin. The company helps the people who control the market price manipu...