본문 바로가기
IT 공부/컴퓨터 하드웨어 및 구조

논리 주소, 물리 주소 차이와 하드웨어적 메모리 보호 기법

by exdus3156 2024. 1. 3.

1. 컴파일 단계에서부터 결정되어야 한다

논리 주소(가상 주소라고보 부른다)를 활용하기 위해서는 컴파일러가 미리 소스코드를 "실행 시간 바인딩(run time binding)"이 가능한 코드로 컴파일해야 한다.

궁극적으로 모든 프로그램은 메모리에 적재되어 CPU에 의해 실행되어야 한다. 따라서 어떻게 CPU가 프로그램의 메모리 상의 주소를 참조해 데이터를 긁어올 수 있는지 표준을 정해야 할 것이다. 컴파일러는 메모리 참조 방식(주소 바인딩, address binding)을 근거로 소스코드를 컴파일해야 한다. 다음은 그 종류다.

 

1-1. 컴파일 타임 바인딩

컴파일 단계에서 구체적인 물리 주소를 결정하는 식이다. 따라서 기계어 명령어에 이미 구체적인 참조 물리 주소가 적히는 식이다. 따라서 프로그램이 적재될 위치도 완전히 고정되어 버린다. 만약 OS가 이 프로그램을 적재하려고 할 때, 특정 메모리 위치에 이미 다른 프로그램이 있다면 이 프로그램은 메모리 자원을 할당받을 수 없다. 사실상 대 컴퓨터에서 거의 사라져버린 주소 바인딩 방식이다.


1-2. 로드 타임 바인딩

컴파일 완료 후, OS에 의해 메모리에 로드될 때 물리 주소가 결정되는 방식이다. 커널의 로더(loader)가 코드를 읽고 구체적인 물리 메모리 주소를 채운 뒤 메모리에 프로그램을 적재한다. 따라서 컴파일러는 반드시 로더가 이러한 작업을 수행할 수 있도록 재배치 가능 코드(Relocatable Code)로 컴파일해야 한다. 역시나 현대 컴퓨팅 환경에서 잘 사용하지 않는 방식이며, 임베디드나 특수 용도 및 제한된 환경의 하드웨어 작업이 요구되지 않는 이상 보기 힘들다.


1-3. 실행 시간 바인딩

현대 컴퓨터가 사용하는 방식으로, 소스코드가 컴파일되고 메모리에 로드될 때에도 여전히 코드 상 물리 주소가 결정되지 않는다. 대신 CPU와 MMU 하드웨어와 주소 매핑 테이블(address mapping table)을 활용해 실행하면서 논리적으로 물리 메모리 주소를 얻어내는 방식이다.

 

 


2. 논리 주소 매핑 방법

CPU와 메모리에 적재되는 컴파일된 코드는 구체적인 물리 주소를 설정받지 않는다. CPU와 코드 모두 0번지에서 시작하는 자신만의 주소로 서로 소통한다. 0번지이기 때문에 컴파일러는 메모리 상의 주소를 고려하지 않고 0번지에서부터 수행된다고 가정할 수 있다. 이것을 가상 주소라고 한다.

 

컴파일러와 OS가 프로그램을 로드할 때 복잡한 물리 주소를 고려하지 않아도 되는 것은 맞지만, 그만큼 가상 주소는 언젠가는 물리 주소로 매핑되어야 할 것이다. 이것은 MMU(Memory Managemanet Unit)라는 하드웨어 장치에 의해 수행된다.

원리는 간단하다. CPU가 명령어를 읽어들여 해석해보니, 10번지의 데이터를 레지스터로 가져와야 한다고 해보자. CPU는 주소가 가상인지 물리인지 신경쓰지 않는다. 10번지의 데이터를 가져오도록 명령을 수행할 것이다.

이 요청이 MMU 장치로 흘러들어간다. 그러면 MMU는 베이스 레지스터(Base Register)의 값과 CPU가 요청한 주소 값을 서로 더한다. 예를 들어, 가상주소가 10이고 BR이 1000이면 결과는 1010이다. 이것이 물리 주소다.

즉, 베이스 레지스터는 실제 물리 주소에 접근하기 위한 offset 오프셋인 것이다. 커널은 프로그램을 적재할 때, 메모리 관리 알고리즘에 따라 적절한 베이스 레지스터를 할당해 프로세스의 위치를 조정할 수 있다. 심지어 실행 도중에 프로세스의 메모리 상 위치가 바뀌어도 오직 베이스 레지스터만 고치면 되는 것이다.

이 베이스 레지스터는 프로세스마다 다르다. 프로세스는 각각의 문맥(context)을 독립적으로 가지고 있다. 레지스터도 포함된다. 따라서 컨텍스트 스위칭 발생 시, 이 레지스터들이 통째로 변경되기 때문에 베이스 레지스터가 섞일 일은 없다.

 

 


3. 하드웨어적 메모리 보안

문제는 이렇게 동적으로 메모리 주소에 접근하는 경우, 자칫 잘못하면 다른 프로세스의 영역을 침범할 수 있다는 사실이다. 

예를 들어, 가상주소가 100번지이고 베이스 레지스터가 1000이면 물리 주소는 1100번지다. 만약 1050 번지 즈음에서 다른 프로세스가 할당되었다고 하면 큰 문제가 될 것이다.

이를 방지하기 위해 또 다른 레지스터인 한계 레지스터(Limit Register)를 둔다. 한계 레지스터는 가상 주소의 최대 한계 범위를 나타낸다. 따라서 가상주소가 한계 레지스터를 넘어버리면 오류를 감지하고 트랩(trap)을 발생시켜 프로세스를 강제 종료한다.

요약하자면, CPU는 오직 가상주소로만 소통하며 가상주소가 진짜 주소라고 가정하고 명령어를 수행한다. 이 가상주소가 물리 주소로 매핑되기 위해 MMU 장치를 거친다. 그러나 다른 프로세스의 영역을 침범하지 않도록 그전에 먼저 한계 레지스터의 값과 비교해 범위를 초과했는지 검증하고, 오류 발생 시 트랩을 시켜 OS가 프로세스를 종료한다.