가상주소란 CPU가 바라보는 논리 주소(Logical Address)와 실제 물리적 RAM의 위치를 분리하여, 각 프로세스가 "자신만의 독립된 거대한 메모리 공간을 통째로 쓰고 있다"는 착각(가상화)을 하게 만든다.
모든 프로세스는 가상 메모리 구조상에서 동일한 시작 주소(예: 0x00000000 또는 낮은 주소 영역)부터 시작하여 메모리를 할당받습니다. 다만 프로그래머들은 이러한 주소영역을 침범할 수 있음에도 안전하게 공존할 수 있는 이유는 하드웨어와 운영체제의 주소공간의 설계방식때문이다.
이 포스팅에서는 파티션 분할과, 베이스 레지스터 두 설계방식이 어떻게 가상 주소공간을 보호하고 있는지 작성한다.
1. 파티션 분할을 통한 영역 보호 (페이지 테이블과 권한 격리)
현대 운영체제는 각 프로세스마다 독립된 페이지 테이블(Page Table)을 부여한다. 프로세스들이 비록 가상 메모리상에서 똑같이 0번지부터 시작하는 주소를 쓴다 하더라도, 실제 물리 메모리의 위치는 페이지 테이블에 의해 완전히 다른 곳으로 매핑된다.
이 가상 주소 공간 내부를 다시 목적과 권한에 따라 여러 개의 파티션(Partition)으로 쪼개어 보호 장치를 둔다.
- 널 포인터 할당 파티션 (최하단 영역): 가상 주소의 시작점인 첫 영역(예: 첫 64KB)은 의도적으로 아무런 물리 메모리도 매핑하지 않고 접근 금지(No-Access) 상태로 둔다.프로세스가 포인터 오류로 잘못된 주소를 참조하면 이 파티션을 건드리게 되어 즉시 예외가 발생하므로, 다른 프로세스나 메모리 영역이 오염되기 전에 차단된다..
- 64KB 접근 금지 파티션 (완충 지대): 메모리 블록이나 파티션 경계 사이에 배치된 빈 공간입니다. 프로그램이 버퍼 오버플로우 등으로 주소를 초과해 벗어나려 할 때, 이 가드 파티션을 밟는 순간 하드웨어가 차단하여 인접한 다른 영역으로 침범하는 것을 막는다.
- 커널 모드 파티션 (최상단 영역): 모든 프로세스가 가상 주소 상의 상단 영역에 운영체제(커널) 파티션을 똑같이 공유하지만, 페이지 테이블의 사용자/커널 모드 비트(U/S Bit)를 두어 보호합니다. 유저 모드 상태인 프로세스는 이 커널 파티션의 메모리를 절대 읽거나 쓸 수 없으며, 오직 시스템 콜을 통해서만 안전하게 접근할 수 있습니다.
2. 베이스 레지스터와 한계 레지스터를 통한 보호
베이스 레지스터(Base Register, 재배치 레지스터)는 연속된 메모리 할당 및 세그멘테이션(Segmentation) 구조에서 하드웨어 레벨로 프로세스의 유효 범위를 강제하는 전통적이면서도 강력한 보호 기법이다.
- 동작 원리:
- 베이스 레지스터: 해당 프로세스가 물리 메모리(또는 할당된 가상 영역)상에서 시작하는 실제 주소를 담고 있습니다.
- 한계 레지스터: 그 프로세스가 사용할 수 있는 메모리의 최대 크기(범위)를 담고 있습니다.
- 보호 메커니즘:
- CPU가 프로세스 내부의 논리 주소를 생성하면, 메모리 관리 하드웨어(MMU)는 주소를 변환하기 전에 이 주소가 한계 레지스터에 설정된 크기보다 작은지 먼저 검사합니다.
- 만약 프로세스가 자신의 허용 범위를 벗어나는(예: 다른 프로세스의 영역을 침범하는) 주소를 요청하면, 하드웨어가 즉시 주소 지정 오류(Trap/Interrupt)를 발생시키고 운영체제가 해당 프로세스를 강제로 중단시킵니다.
- 범위 내에 있다면, 베이스 레지스터의 값을 더해 안전한 자신의 영역 안에서만 연산이 일어나도록 보장합니다.
