프로그램을 실행할때 하나의 함수가 수행되는 중에 다른 함수를 호출하고 호출된 함수의 수행이 완료되면 다시 원래 호출되었던 함수의 위치로 돌아가 프로그램을 계속해서 수행한다. 그리고 프로그램이 CPU에서 명령을 수행하려면 해당 명령을 담은 프로그램의 주소 영역이 메모리에 적재되어 있어야 한다.
프로그램의 주소 영역은 code, data, stack으로 구분된다.
함수 a가 수행 중에 b라는 함수를 호출할 경우
인터럽트의 동작 방식도 함수의 호출과 비슷하다.
일반적으로 프로그램 내에서 발생되는 함수 호출에 대한 복귀 주소는 각 프로그램의 주소 공간 중 스택 영역에 보관한다. 인터럽트 때문에 CPU를 빼앗긴 위치는 운영체제가 관리하는 PCB에 저장된다.
CPU는 매 시점 메모리의 특정 주소에 존재하는 명령을 하나씩 읽어와 그대로 실행한다. CPU가 수행해야할 메모리 주소를 담고 있는 레지스터를 프로그램 카운터(Program Counter, PC)라고 한다. 즉, CPU는 PC가 가리키는 메모리 위치의 명령을 수행한다.
메모리에는 프로그램과 운영체제가 같이 올라가서 수행된다.
CPU가 수행하는 명령: 일반명령, 특권명령
모드 비트로 두 명령의 실행가능성을 항상 확인함
만약 프로그램이 특권명령의 수행이 필요할 경우, 운영체제에게 특권명령 대행을 요청하게 되는데 이것을 시스템콜이라고 한다. 시스템콜을 하게 되면 운영체제는 프로그램의 코드가 아닌 커널 영역에 정의된 시스템 콜 코드를 수행하게 된다.
CPU는 PC가 가리키는 곳의 명령만 수행하기 때문에 주변장치의 상태를 지속적으로 파악할 수 없다. 따라서 주변장치는 인터럽트를 사용하여 CPU가 필요할 때마다 요청을 보낸다. 인터럽트를 발생시키기 위해서 주변장치는 인터럽트 라인을 세팅하고 CPU는 매번 명령을 수행한 직후 인터럽트 라인을 체크해 요청이 들어왔는지 확인하게 된다. 인터럽트가 발생하면 CPU는 해당 인터럽트를 처리하기 위한 루틴으로 넘어가 커널 내의 인터럽트 처리 코드를 수행한다.
프로그램이 실행 중이다 : Process
메모리 공간을 효율적으로 사용하기 위해 실행파일의 모든 부분이 메모리에 적재되지 않고 일부분만 메모리에 올라가고 나머지는 디스크의 특정 영역에 내려가 있는 것이 일반적이다. 즉, 프로그램의 주소 공간 중 CPU 수행에 당장 필요한 부분은 메모리에 적재, 아닌 부분은 디스크의 스왑 영역에 내려놓는 방식으로 운영된다.
각각의 프로그램들은 프로세스 주소 공간을 별도로 갖고 있으며 프로그램마다 독자적으로 존재하는 이와 같은 주소 공간을 가상메모리 또는 논리적 메모리라고 부른다. (실제 물리적 메모리 주소와 독립적으로 각 프로그램마다 독립적인 주소 공간을 가지므로 지칭하는 용어임)
운영체제의 커널도 코드, 데이터, 스택 등의 주소 공간 구성을 갖고 있다.
프로그램이 자신의 코드 내에서 함수 호출 및 복귀 주소를 유지하기 위해서는 주소 공간 내의 스택을 사용하되, 시스템 콜이나 인터럽트로 인해 커널의 코드가 실행중에 함수 호출이 발생했을 때에는 커널 스택을 사용한다.
프로그램 내의 함수 호출시 해당 프로그램의 스택에 복귀 주소를 저장하지만 시스템 콜이나 인터럽트 발생으로 CPU 수행 주체가 운영체제로 바뀌는 순간에는 직전에 수행되던 프로그램의 복귀 정보를 스택이 아닌 PCB에 저장한다는 점을 주의해야 한다.
커널의 코드가 수행되는 도중에 이루어지는 함수 호출은 커널 스택에 저장한다.