민혁이의 IT스토리

[Pintos - UserPrograme] - Register와 Memory 본문

Pintos/UserPrograme

[Pintos - UserPrograme] - Register와 Memory

FE_Minhyuk 2025. 11. 24. 11:49

 

 


 Register


 

레지스터는 CPU 내부에 있는 아주 빠른 저장소입니다. 하지만 OS 이론 관점에서 볼 때 레지스터의 진정한 역할은 문맥(Context) 저장소 이자 커널과의 메신저입니다.

 

문맥 교환 (Context Switching)의 핵심

CPU는 한 번에 하나의 일만 처리할 수 있습니다. 유저 프로그램 A를 실행하다가 커널이 개입하거나 다른 프로그램 B로 넘어가야 할 때, A가 계산 중이던 값들은 어디로 갈까요?

이때 레지스터에 있던 모든 값들은 메모리(커널 스택)에 스냅샷처럼 백업됩니다. 그리고 나중에 다시 A 차례가 오면 백업해 둔 값을 레지스터로 복구합니다.

즉, 레지스터 값 그 자체가 프로그램의 현재 실행 상태를 의미합니다.

커널과 유저의 메신저 (Messenger)

앞서 메모리 섹션에서 유저와 커널은 서로의 영역을 침범할 수 없다고 했습니다. 그렇다면 유저 프로그램이 "파일을 읽어줘"라고 커널에 요청할 때는 어떻게 소통할까요?

바로 레지스터를 이용합니다. 레지스터는 CPU의 부품이므로 메모리 영역의 제한을 받지 않는 공용 트레이와 같습니다.

  1. 보내는 쪽지 (Arguments): 유저가 특정 레지스터(트레이)에 요청 내용(인자)을 담습니다.
  2. 호출 (Syscall): 유저가 CPU에게 신호를 보냅니다.
  3. 읽는 쪽지 (Parsing): 커널은 레지스터를 확인해 유저가 무엇을 원하는지 파악합니다.
  4. 답장 (Return Value): 일을 마친 커널은 특정 레지스터에 결과값을 남겨두고 떠납니다.

 


Memory


운영체제에서 메모리는 단순한 저장 공간을 넘어 영역(Territory)의 개념이 강합니다. Project 2에서 메모리를 이해할 때 가장 중요한 핵심은 공간 분리와 초기 세팅 입니다.

 

가상 메모리의 분리 (User Space vs Kernel Space)

하나의 프로세스는 자신만의 거대한 가상 메모리 공간을 가지고 있다고 착각합니다. 하지만 운영체제는 이 공간을 엄격하게 두 구역으로 나눕니다.

  • User Space (유저 영역): 유저 프로그램의 코드, 데이터, 스택이 존재하는 곳입니다. 프로그램은 이곳에서만 자유롭게 읽고 쓸 수 있습니다.
  • Kernel Space (커널 영역): 운영체제의 핵심 코드가 존재하는 곳입니다. 유저 프로그램이 이곳을 침범하려고 하면 OS는 즉시 해당 프로그램을 강제 종료(Page Fault) 시킵니다.

핵심: 메모리 관리의 첫 번째 목표는 유저가 절대 커널 영역을 넘보지 못하게 막는 것 입니다.

 유저 스택 (User Stack)의 역할

프로그램이 함수를 호출할 때 지역 변수가 저장되는 곳이 스택입니다. 하지만 프로그램이 '처음 시작될 때' 스택은 조금 특별한 역할을 합니다.

프로그램이 실행되려면(예: ls -l 입력) 누군가가 이 명령어와 옵션(-l)을 프로그램에게 전달해 줘야 합니다. OS는 프로그램이 시작되기 직전, 유저 영역의 스택(Stack)에 이 데이터들을 미리 예쁘게 포장해서 넣어둡니다.

즉, 메모리(스택)는 프로그램 실행을 위한 준비물이 놓이는 선반 역할을 합니다.

 

 


Memory와 Register의 협업


 

상황 A: 프로그램 시작 (Argument Passing)

  1. [Memory] 데이터 배치: 커널은 유저 스택 메모리 공간(User Space)을 할당하고, 그 안에 파싱 된 명령어 인자들과 포인터 배열을 규약에 맞춰 씁니다.
  2. [Register] 위치 지정: 데이터를 다 쓴 후, "스택의 꼭대기가 여기야"라고 알려주기 위해 스택 포인터 레지스터(%rsp)를 설정합니다. 그리고 main() 함수가 인자를 찾을 수 있도록 %rdi(argc), %rsi(argv) 레지스터를 세팅하고 프로그램을 시작시킵니다.

 

상황 B: 시스템 콜 호출 (System Call)

  1. [Register] 요청 전달: 유저 프로그램은 작은 데이터(파일 디스크립터 번호, 시스템 콜 번호 등)를 레지스터에 직접 담아 보냅니다.
  2. [Memory] 대용량 데이터 전달: 만약 write()처럼 긴 문자열을 보내야 한다면? 레지스터는 너무 작습니다. 이때 유저는 데이터를 **자신의 메모리(User Memory)**에 써두고, 레지스터에는 그 **데이터가 위치한 메모리 주소(포인터)**만 담아서 보냅니다.
  3. [Validation] 검증: 커널은 레지스터를 통해 전달받은 그 '주소'가 정말 유효한 유저 영역인지 검사한 후, 해당 메모리에 접근하여 데이터를 읽습니다.

 

 

 

마무리

 

 

  • Memory는 철저히 격리된 공간이며, 커널은 유저 메모리에 데이터를 올바르게 배치(Stack Setup)하고 검증(Address Check)해야 한다.
  • Register는 격리된 두 세계를 잇는 다리이며, 시스템 콜 시 인자와 결과값을 전달하는 매개체이자 프로그램의 실행 흐름을 기억하는 저장소다.

 

'Pintos > UserPrograme' 카테고리의 다른 글

[Pintos - UserProgrames] - User Mode와 Kernel Mode  (0) 2025.11.23