가상 메모리 영역

Posted 2012. 10. 18. 14:41

1. 코드 영역

말그대로 코드들


2. 데이터 영역 

프로그램이 종료 될 때까지 지워지지 않을 데이터 저장 공간. 

전역 변수, static 변수, 초기화된 배열과 구조체


3. 스택 영역

잠깐 사용하고 삭제할 데이터 저장 공간

지역변수, 매개변수, 복귀번지


4. 힙 영역

사용자에 의해 만들어진 공간( new, delete )

Little Endian, Big Endian

Posted 2012. 10. 18. 14:12

다중 바이트로 이루어진 수를 단일 주소를 가진 하나의 데이터로 다루어야 할 필요가 있을때

어떠한 바이트 순서로 그 데이터를 배열 할 것인지를 엔디안(Endian)이라 한다.


아래의 123이 최상위 바이트( MSB : Most Significant Byte )

0x12345678

뒤의 678이 최하위 바이트( LSB : Least Significant Byte )


리틀 엔디안 : 낮은 주소에 최하위 바이트를 저장하는 방식

빅 엔디안 : 낮은 주소에 최상위 바이트를 저장하는 방식


 리틀 엔디안 방식↓

메모리 주소 

 메모리 내용

 0

 78

 56

 34

 12

빅 엔디안 방식↓

메모리 주소 

 메모리 내용

 0

 12

 34

 56

 78


각각 장점이 있는데 별 차이는 없고 다만 기계들과의 호환성에 문제가 있다.

인텔 계열은 리틀이고 morolora, 등등은 빅 엔디언 이다.

Memory Management Unit

Posted 2012. 10. 18. 12:22

MMU : 메모리 관리의 핵심적인 역할을 담당한다. 실제 메모리와 가상 메모리 사이에서 주소 변환

역할을 한다.


cpu가 사용 하는 주소 : 가상주소 ( virtual address )

memory가 사용하는 주소 : 물리적 주소( physical address )


컴퍼는 수행할 명령어의 주소를 가르켜야 하는데 이떄 가지는 값이 virtual address다.


MMU의 중요한 기능인 두 가지 이다.

1) HAT( Hardware Address Translation )

세그먼트와 페이징을 담당한느 하드웨어 부분.

실질적인 주소변환연산을 한다. H/W레벨에서 모두 처리 하며 연산된 결과는 TLB에

저장된다.


2) TLB( Translation Lookaside Buffer )

가상 메모리 시스템에서 페이징 작업을 수행하기 위해 가상 메모리의 내용을 실제 메모리값으로

변환하는데에는 많은 시간이 소요된다. TLB는 캐시의 개념을 이용 한 것으로 일정 개수만큼의

변환 내용을 버퍼에 보관하여 놓음으로써 변환에 드는 시간을 주여준다.


둘 다 MMU내에 존재한다.


TBL 미스 발생시 우선 페이지 테이블을 찾는다. 페이지 테이블도 페이지 프레임에 있기때문에

TLB검색이 발생한다. 만약 페이지 테이블을 담고있는 페이지 프레임의 정보가 TLB에 없다면

추가적인 TBL미스가 발생한다. 이런 반복이 큰 문제가 된다. 해결 방안으로 TLB엔트리를

위한 큰 소프트웨어 캐시를 사용하는 것이다. 이 개시는 고정된 위치에 있다.

이를 위한 페이징 저보는 항상 TLB에 존한다. OS는 소프트웨어 캐시를 먼저 검색함으로써

반복적인 TLB 미스를 줄일 수 있다.

soft miss : 참조하려는 페이지가 메모리에 있지만 TLB에 정보가 없어서 발생하는 결함

hard miss : TLB뿐만 아니라 메모리에도 참조하려는 페이지가 없으면 디스크I/O 발생



이런 MMU가 나온 이유는 메모리관리를 위해 완전히 소프트웨어가 담당하였던 것을

x86 386이후 운영체제를 만들때 소프트웨어적인 부담을 훨씬줄여주기 위해서 였다.

절대주소, 세그먼트, 오프셋

Posted 2012. 10. 18. 11:39

절대주소 : 0H 부터 시작되는 실제주소

세그먼트 : 메모리의 구분을 위해 사용되는 주소

오프셋 : 세그먼트에 대한 상대주소


프로그램에 실행되면 메모리에는 프로그램 코드와 데이터.. 그 외의 여러가지 코드들이 등록된다.

그것을 모두 절대주소로만 사용하기보단 종류별로 나누어 뒀다. 나눈게 세그먼트이다.


대표적인게 CS( Code Segment ) , DS( Data Segment )

실제 데이터가 등록된 시작 주소는 DS:0000이고

프로그램 실행코드가 등록된 시작주소가 CS:0000이다.

세그먼트는 10H단위다. 데이터가 1000H부터 등록 되었다면

DS는 10H단위이므로 1000H / 10H 즉 100H가 된다.


이거의 절대주소를 구하는 방법은 DS * 10H * 오프셋 이다.


세그먼트 : 오프셋으로 가질 수 있는 최대값은 16^6 = 2^20 = 1MEGA이다.


컴퓨터 설계될때 그렇게 정해져 있다.


세그먼트는 프로그램 실행시 모두 정해지며 오프셋으로 해당 위치를 찾는다.

오프셋은 음수를 가질수 없다. 세그먼트도 마찬가지 이다.



이게 왠 어셈블리어...

페이징이란 ?

Posted 2012. 10. 17. 17:34

인텔의 보호모드에서는 사용자가 입력한 논리적 주소에 대하여 세그먼트 레지스터가 지시하는 세그먼트 디스크립터의 베이스 주소 값과 합해져 새로운 선형 주고를 만들어 내게 된다.

그리고 이렇게 만들어진 선형 주소는 다시 페이지 디렉토리의 인덱스, 페이지 테이블의 인덱스, 그리고

오프셋으로 사용되어 실제 물리 주소를 지시하게 되며, 선형 주소에서 물리주소까지 얻어지는 과정을

페이징(Pasing)이라 부른다.


32비트의 선형주소 체제는 인텔 마이크로프로세서의 페이징  과정을 거쳐 실제의 물리 어드레스로 

지시된다.

페이징 이라는 과정이 수행하는 일은 32비트의 선형 주소 체제에 해당되는 4Gbyte의 메모리르 이보다

작은 용량의 실제 메모리 주소와 매핑시켜주는 일을 하게 되며 실제 물리적으로 가지고 있는 메모리가

부족할 경우 하드디스크와 같은 보조적인 기억장치의 도움을 받아 실제 물리적 메모리량보다 큰 용량

의 메모리를 사용할 수 있도록 해준다.


우선 32비트의 선형 주소를페이지 디렉토리 인덱스( Page Directory Index ), 페이지 테이블 인덱스

( Page table Index ), 그리고 오프셋(Offset)의 3부분으로 나눈후 CPU의 CR3 레지스터가 가리키고 있는 페이지 디렉토리와 선형 주소로 부터 얻은 페이지 디렉토리 인덱스를 사용하여 페이지 테이블의 포인터를 얻고 이 페이지 테이블의 포인터와 선형 어드레스으 ㅣ페이지 테이블 인덱스를 사용하여

실제 물리 주소의 페이지를 얻은 후 오프셋을 더하여 최종적인 물리적 주소를 얻어내게 된ㄷ.


CR3 레이즈터

선형 주소를 실제 물리적 주소로 바꾸기 위한 첫번째 작업은 페이지 디렉토리를 찾는 것이며

이 페이지 디렉토리의 위치 정보는 CR3( Control Register 3 )레지스터의 11비트에서 31비트

사이의 20비트를 통하여 얻게된다.

windows에서 프로세스의 스위칭이 일어 날 때마다 CR3 레지스터의 페이지 디렉토리 PFN을 바꾸어

줌으로써 해당 프로세스가 사용하는 가상 메모리를 전혀 다른 물리적 주소와 매핑시킬수 있게 한다.



페이지 디렉토리

32비트의 페이지 디렉토리 엔트리 정보를 1024개 만큼 가지고 있는 배열 형태의 구조이며, 하나의 프로세스에는 반드시 하나의 페이지 디렉토리가 존재해야 한다.

이전 단계의 CR3 레지스터에 의하여 발견하게 된 페이지 디렉토리( Page Directory )에서 어떠한 엔트리를 선택할것인지는 32빙트의 선형 주소 중 22~31비트 사이의 10비트를 인덱스로하여 선택하게 된다



페이지 테이블

페이지 테이블 중에 어떤 엔트리를 사용할 것인지는 선혀 ㅇ메모리의 12~21비트 사이의 10비트를 인덱스로사용하여 결정하게 된다.

유저레벨, 커널레벨

Posted 2012. 10. 17. 15:57

과거나 지금이나 컴퓨터 보안 또는 시스템 보호에 대해서 많은 논의가 되고 있다.

미숙한 사용자가 중요한 파일을 삭제한다던데 의로적인 악성코드로 인해 시스템이 멈추어 버린다던지

이런 위험요소에서 시스템을 보호하는 것은 매우 중요한 일이다.


인텔은 80286프로세서를 디자인 할때 시스템 보호에 대해 만은 고민을 해 왔으며

이들 중 가장 효과정인 방법으로 마이크로프로세서 내의 MMU( Memory Management Unit )에서의

보호 매커니즘을 생각하게 되었다.


App code  :   PL 3            :: Aookications

PL 2                                :: Operation System Service

PL 1                                :: Operation System Service

OS Code : PL 0                :: Operation System Kernel


PL 3 에서 PL 0 으론 특별한 방법에 의해 접근 가능하다.


이방법은 어떠한 프로그램이든 메모리에 있는 코드 내용에 의해 실행이 되어지며 이러한 메모리에 대해

어떠한 명령어가 참조하고자 할 때 그 명령을 실행하는 코드 메모리와 접근하는 메모리의 권한을 체크하여 프로세서 차원에서의 보호가 가능하게 하는것으로 인텔에서는 이러한 것을

멀티링 이라는 형태로 디자인 하였다.


보호 규정

1. 특권 수준이낮은 코드 세그먼트가 특권 수준이 높은 데이터 세그먼트로 엑세스 하는 것은 불가능하다

2. 특권 수준이 낮은 코드 세그먼트에서 특권 수준이 높은 코드 세그먼트로의 제어 이행은 특별한

방법을 사용해서만 가능하다

3. 특권 수준이 높은 코드세그먼트에서 특권 수준이 낮은 코드 세그먼트로의 제어 이행이 불가능하다.


커널모드를 Ring0 이라 하고, 유저모드를 Ring3 이라 한다.


인텔 마이크로프로세서으 ㅣ세그먼트 디스크립터에는 그 디스크립터가 가지는 특권 권한값을

나타내는 DPL 필드를 가지고 있다. 현재 실행중에 있는 코드 세그먼트 디스크립터가 가지는

DPL값을 우리는 CPL이라 부르며( Current Privilege Level ) 이 값이 바로 현재 실행되고 있는

코드의 권한이 된다.


당연히 낮은 권한으로 높은 권한으로의 접근은 불가능 하다.

메모리관리기법

Posted 2012. 10. 17. 15:53

모든 프로그램이 메모리에 올라와서 사용하게 된다. 이런 메모리르 확장 시켜줄 수 있는

기법이 가상 메모리 (virtual memory )기법 이고 현대 운영체재 시스템에

가장 핵심이 되는 기술이다. 이 가상 메모리를 가능하게 하는 기술로

페이징. 세그먼트, 병합 기법이 있다.



1. 페이징 기법

페이징은 하나의 프로그램을 각각의 페이지 프레임(4KB)로 나누고 이를 메모리에 올려서 사용하는

방식이다. 이떄 가상의 주소로 작성되어있는 각 페이지 프레임은 페이지 테이블에 의해 실제 주소로

매핑되게 된다. 이렇게 함으로써 페이지 테이블을 처리해야 하는 일이생기고 메모리 낭비

효과도 가져온다.

만약 프로세스 하나가 지시 할 수 있는 메모리가 4GB까지 되고(32bit) 페이지 테이블에 존재하는

매핑 페이지 프레인 정보를 나타내는 데 4byte의 크기를 가진 가상 메모리를  구성하면

페이지 테이블 크기는 얼마나 될까..

단순히 1048576 x 4 byte 하면 그 크기는 4MByte가 된다. 그럼 이 시스템에서 3개의 프로세서가

실행되고 있다면 얼마나 될까.. 이는 4MByte x 3 하면 12MByte가 되며 단순히 메모리의 매핑 정보를

나타내는 데 이 큰 용량이 낭비된다는 의미이며 프로세서가 100개, 200개 늘어나면 그 크기는 엄청나다.

인텔 80x86계열에서 제공하는 메모리 매니저 유닛은 이와 같은 낭비를 줄이기 위해 가상 메모리

주소에서 위 페이지 테이블 인덱스 부분을 다음과 같이 페이지 디펙토리 인덱스와 페이지 테이블

인덱스 두 부분으로 나누어 페이지 디렉토리 부분에 해당하는 목록만 메모리에 올려놓고

페이지 테이블에 대해서는 필요시에만 만들어 메모리에 올려놓음으로써 낭비를 줄이고 있다.


페이징 기법에 의하여 메모리가 엑세스 되어진다면 매번 메모리를 차조할 때마다 페이지 테이블의 

내용을 참조하여 실제 메모리를 계산해야 하는 낭비가 생긴다.

이를 보완이 필요한데 인텔 MS는 TLB(Translation Lookaside Buffer)라는 버퍼를 두고 이곳에

변환에 사용되었던 가상 주소와 위치 정보와 실제 매핑되어진 메모리의 위치 정보를 일정 개수만큼

유지함으로써 다음번 메모리 변환 시에서 해당 가상 메모리 위치를 참조할 경우 이 영역을 참조함으로

변환에 드는 시간을 줄이고 있다.



2. 세그먼트 기법

페이징 기법과 원리는 같다. 하지만 각각의 세그먼트는 그 크기가 고정되어 있지 않다.

예를 들어 컴파일러가 응용프로그램을 만들때 코드부분, 리소스부분, 디버깅 정보 부분같이 서로

연관된 부분을 메모리에 올려 처리 효율을올리는 방식이다. 이 기법은 메모리 단편화 현상이라는

약점이 있다.

메모리 단편화 : 서로 다른 크기의 세그먼트들에 대하여 필요시 메모리에 올리고 필요가 없어지면

내리는 작업을 오랫동안 반복하다 보면 외부단편화가 생긴다( Fragmentation ). 외부단편화란

용량이 큰 빈 메모리 공간은 줄어들고 작은 메모리 공간들이 점점 늘어남으로써 실제로 큰 세그먼트가

들어갈 수 있는 공간이 없어지는 경우를 말한다.

단편화를 없애려면 세그먼트들을 재배치 하여 큰 공간을 마련해야 하는데 그런작업은 오버헤드를

일으키게 된다.

이것을 보안하기 위해 페이징+세그먼트 병합기법을 만들게 된다.




3. 세그먼트와 페이징 기법의 병합

각각의 장점만 가지고 있다.

페이징의 경우 외부 단편화가 존재하지 않고 주기억장치를 효율적으로 사용할 수 있으며

세그먼트의 경우 가변적인 자료 구조, 모듈성으 ㅣ처리, 공유와 보호를 지원하는 장점을

가지고 있다.




마이크로프로세서에서 명시적 혹은 암시적으로 지시되어지는 세그먼트 레지스터와 사용자가 지정한

메모리를 조합하는 과정을 우리는 세그먼테이션 이라 부르는데.

이 작업은 세그먼트 디스크립터에 정의되어 있는 여러가지 보호 속성과 제한 속성을 통하여 시스템에

보호 작업을 수행하게 된다.


세그먼테이션 과정을 통해 세그먼트 레지스터와 사용자가 지정한 32비트의 논리적주소(Local address

가 합해져서 새로운 32비트의 선형주소(linear address)가 만들어 진다.



폰 노이만 아키텍쳐

Posted 2012. 10. 16. 18:19

1. 컴퓨터 아키텍처의 기본

컴퓨터는 크게 입력,연산,저장,출력 장치로 나눌수 있다.

입력/출력 장치는 말 그대로 키보드 모니터 같은 거고

연상장치와 저장장치는 주로 Computer Architecture에서 다룬다.


2. 폰 노이만 아키텍쳐 , 하바드 아키텍쳐

둘다 Stored Program Concept를 따르는 아키텍쳐다.

Stored Program Concept란

1 + 1 = 2 라는 계산을 컴퓨터로 한다면

1. Fetch : 1 + 1 을 해 달라고 컴퓨터 에게 입력한다.

2. Decode : 컴퓨터는 받은 명령을 해석한다.

3. Execute : 컴퓨터는 1과 1을 더해 2를 만들어 낸다.

4. Store : 결과를 보여준다.

이런 순서를 반복하는것.

이런 Stored Program Concept를 Von Neumann(폰 노이만) 박사가 1945년 제안하였고

현재 가장 많이 사용하고 있다. 이런 Stored P..... 를 사용한 구조를 폰 노이만 아키텍처라 한다.

여기서. 데이터는 메모리에서 읽거나 메모리에 쓰기도 하는 반면..

명령어는 메모리에서 읽기만 하는 구조가 폰 노이만 아키텍처다.

특징은 프로세서에게 메모리 특정 지점부터 실행하도록 지시 할 수 있다.

이때 데이터와 명령어 사이에 뚜렷한 구분이 없어서 주어진 내용을 무조건 실행한다.

데이터 자체에 고유 의미가 없고 이를 해석하는 프로그램에 의해 의미가 달라진다.

데이터와 명령어는 메모리를 공유하며 특정 프로그램에서 명령어인 내용은 다른 프로그램에서

데이터 일수 있다.



하바드 아키텍처

명령어와 데이터 통로를 저장공간과 물리적으로 분리한 아키텍처를 말한다.

폰 노이만 아키텍처와 다르게 CPU는 메모리로부터 명령어를 읽거나 데이터를 읽고쓰고가 동시에 가능

하다. 그러나 명령어와 데이터 같은 신호 통로와 메모리를 동시에 사용하지 않는다.

하바드 아키텍처 컴퓨터에서는 CPU는 메모리로부터 명령어와 데이터를 동시에 사용할수 있고

현재 명령을 마치는것과 동시에 다음 명령을 가져 올 수 있기 때문에 속도가 더 빠르다.

하지만.. 가격이 더 비싸다던데..



뭐.. 1~4번을 하나의 싸이클로 보면

1~4번 작업이 끝날때 하나의 결과를 받을 것이다.

작업이 다 끝나야 다음 작업이 실행되고..

결국 작업 중인 번호 외엔 놀고있는거다.

이 놀고있는 시간이 무언가 다른 작업을 하면서 속도를 올리는게 파이프라이닝 이란것..

즉 겹치지 않는 곳에서 할일을 하는것이다.


폰 노이만 : 중앙처리장치 중심의 구조로 중앙집권식 명령처리. 데이터메모리와 프로그램 메모리가 구분되어있지않고 하나를 가지는 구조


하버드 아키텍처 : 중앙처리장치 없는 병렬식 구조. 지방분권식 명령처리.

데이터 메모리와 프로그램 메모리가 서로 다른 버스를 사용하는 구조로 명령과 데이터를

동시에 읽어 들일 수 있다.

텍스트 파일은 글자들이 씌어있는 파일이다.

사람이 눈으로 직접 내용을 읽을 수 있다.

텍스트 파일은 아스키 파일 이라고도 한다.

대부분의 텍스트 파일이 아스키코드로 글자들을 나타내기 때문이다.

대표적인 확장자가 txt 이고 그밖에 .c, .cpp .bat, .java, .xml 등등 각종 프로그램이 소스들과 웹문서도

텍스트 파일이다.



바이너리 파일은 0과 1로 이루어진 이진 파일을 말한다.

직접 읽긴 힘들고 .exe, .dll처럼 프로그램 파일과 zip, rar같은 압출파일, gif,mp3같은 멀티미디어 파일이다.



엄밀히 말하면 텍스트 파일도 바이너리 파일의 일부분이다.

제한된 형태일 뿐이다.



작업시엔 fread 할때

text파일은 끝을 명확히 알수 있는 반면에 바이너리 파일은 어디가 끝인지 구분하기 힘들어

읽을 부분을 제대로 설정 할 수가 없다.


Text파일의 인코딩 방법 알아보기

Posted 2012. 10. 16. 13:46

인코딩 탕입이란 특정 캐릭터셋으로 만들어진 파일을 보여주는 방식이다.

전세계 주요 언어문자를 하나의 바이너리 코드로 처리하기 위해서 유니코드로 만들었지만

이 코드를 보여주는 인코딩 방식은 다양하다.

텍스트 파일이 어떤 인코딩 타입으로 설정되어 있느냐에 따라 똑같은 유니코드 데이터도 제대로

보이기도 안보이기도 한다. 그래서 어떤 인코딩타입으로 되어 있는지 알아내야 한다.


텍스트 파일엔 인코딩 방법이 여러가지가 있다

1. 안시

2. Unicode( little Endian )

3. Unicode( big Endian )

4. UTF-8

txt파일 -> 다른이름 저장 -> 하면 인코딩 방식 메뉴 있음.

상대방이 어떤 방식으로 작업을 했는지 통보를 받지 못하는 경우도 생긴다.

파일을 읽기전에 인코딩 방식을 알아본뒤 작업하자.

인코딩 방식을 알아보려면 파일을 3바이트만 읽어오면 된다.

3바이트 읽는 이유는 각각 방식들이 나타내는 비트가 있는데 UTF-8은 바이트가 필요하기 때문이다.

나머진 2바이트면 됨.(비트들은 16진수로 되어있다)


#include <stdion.h>

#include <string.h>

#include <ctype.h>

#include <windows.h>


int CheckEncoding( BYTE *str )

{

int iRet = 0;

BYTE Unicode_L[] = {0xFF, 0xFE};        // 유니코드 리틀

BYTE Unicode_B[] = {0xFE, 0xFF};        // 유니코드 빅

BYTE UTF_8[] = {0xEF, 0xBB, 0xBF};     // UTF-8


if( memcmp( str, Unicode_L, 2 ) == 0 )    // 메모리비교를 해야한다.

{

iRet = 2;

}

else if( memcmp( str, Unicode_B, 2 ) == 0 )

{

iRet = 3;

]

else if( memcmp( str, UTF_8, 3 ) == 0 )

{

iRet = 4;

}

else

{

iRet = 1;

}

return iRet;

}


void main()

{

BYTE buf[3];

memset( buf, 0, 3 );


FILE *p = fopen("abc.txt", "r");

fread( buf, sizeof(BYTE), 3, p );

fclose( pf );


int Ret = CheckEncoding( buf );

switch( Ret )

{

case 1:

printf("Encoding : ANSI \n");

break;

case 2:

printf("Encoding : Unicode_L \n");

break;

case 3:

printf("Encoding : Unicode_B \n");

break;

case 4:

printf("Encoding : UTF-8 \n");

break;

default:

break;

}

}