Structure_1

Kamator0·2026년 4월 12일

사용자-OS 인터페이스 (User Operating System Interface)

사용자가 운영체제와 소통하는 두 가지 방식이 있다.

  1. CLI (Command Line Interface, 명령줄 인터페이스)
  • CLI(명령 해석기)는 직접 명령어를 입력할 수 있게 한다.
  • 때로는 커널 안에 구현되기도 하고, 때로는 시스템 프로그램으로 구현되기도 한다.
    - 커널 안에 구현된 경우: 명령 해석 기능이 OS 핵심에 포함됨
    - 시스템 프로그램으로 구현된 경우: 별도의 프로그램(셸)으로 동작
  • 여러 종류의 명령 해석기를 셸(shell)이라고 부른다.
    - ex : bash, zsh, csh, fish 등 다양한 셸이 존재한다.
    - 셸의 핵심 기능은 사용자로부터 명령을 받아 실행하는 것이다.
    • ex : 사용자가 ls -la를 입력하면, 셸이 이 명령을 해석하여 파일 목록을 보여주는 프로그램을 실행한다.
  1. GUI (Graphical User Interface, 그래픽 사용자 인터페이스)
  • 사용자 친화적인 데스크톱 비유 인터페이스이다.
    - "데스크톱 비유 (desktop metaphor)"란 실제 책상 위의 물건(폴더, 파일, 휴지통 등)을 화면에 그대로 재현하는 방식이다.
  • OS와의 인터페이스는 마우스, 키보드, 모니터를 통해 이루어진다.
    - GUI는 마우스 기반의 창(window)과 메뉴(menu) 시스템을 제공하며, 이를 데스크톱이라 부른다.
  • CDE (Common Desktop Environment): 상용 유닉스 시스템에서 사용
    GNOME: 리눅스 시스템에서 널리 사용되는 데스크톱 환경

현대 시스템의 인터페이스

현대의 많은 시스템은 CLI와 GUI를 모두 포함한다.
운영체제인터페이스 특징Microsoft WindowsGUI 중심 + CLI "command" 셸 (cmd, PowerShell)SolarisCLI 중심 + 선택적 GUI (Java Desktop, KDE)

핵심 포인트: CLI는 텍스트 명령 기반으로 강력하고 자동화에 유리하며, GUI는 직관적이고 사용이 쉽다. 현대 OS는 대부분 두 가지를 모두 제공한다.

시스템 콜과 API (System Call and API)

시스템 콜의 정의

  • 운영체제가 제공하는 서비스에 대한 프로그래밍 인터페이스이다.
    시스템 콜은 응용 프로그램이 커널의 서비스(파일 읽기, 프로세스 생성, 메모리 할당 등)를 요청하는 유일한 방법이다.

implementation of system calls

  • 일반적으로 고수준 언어(C 또는 C++)로 작성된다.

API의 정의

  • 응용 프로그래머에게 사용 가능한 함수 집합이다.
  • API 집합은 보통 OS 위에 있는 미들웨어 계층에 의해 제공된다.
  • 대부분의 응용 프로그램은 고수준 API를 사용하며, 시스템 콜을 직접 사용하지는 않는다.

ex : 프로그래머는 printf()같은 API 함수를 호출하고, 이 API가 내부적으로 write() 같은 시스템 콜을 호출한다. 프로그래머가 직접 시스템 콜 번호를 지정할 필요가 없다.

API 예시

API대상 시스템 Win32 API, WindowsPOSIX API POSIX 기반 시스템 (UNIX, Linux, Mac OS X 거의 모든 버전)Java API Java 가상 머신 (JVM)

왜 시스템 콜 대신 API를 사용하는가?

  • 호환성 — 응용 프로그래머는 같은 API를 지원하는 어떤 시스템에서든 자신의 프로그램이 컴파일되고 실행될 것을 기대할 수 있다.
    - 예: POSIX API로 작성된 프로그램은 Linux에서도 FreeBSD에서도 실행 가능하다.
  • 정보 은닉 — 실제 시스템 콜은 API보다 더 상세하고 사용하기 어려운 경우가 많다.

API가 복잡한 시스템 콜의 세부 사항을 감추어 프로그래밍을 쉽게 한다.

그림은 API의 호환성(portability)을 보여준다:

  • Linux 위의 POSIX 응용 프로그램 → FreeBSD로 이동 가능 (같은 POSIX API이므로)
  • Linux 위의 POSIX 응용 프로그램 → Windows XP(Win32)로는 이동 불가능 (X 표시, API가 다르므로) (Sys call num 이 다르다는 것)
  • 단, Windows XP 위에 cygwin을 설치하면 POSIX API를 지원하므로 이동 가능

핵심 포인트: API를 사용하면 OS가 달라져도 같은 API를 지원하는 한 프로그램을 재컴파일 없이 또는 최소한의 수정으로 이식할 수 있다. 이것이 API의 가장 큰 장점이다.

API – 시스템 콜 – OS 관계 (API – System Call – OS Relationship)

흐름 정리:

  1. 사용자 응용 프로그램이 open() API 함수를 호출한다.
  2. 시스템 콜 인터페이스를 통과하면서 커널 모드로 전환된다.
  3. 커널은 시스템 콜 번호 i를 이용해 sys_call_table에서 해당 커널 루틴을 찾는다.
  4. open() 시스템 콜의 실제 구현(커널 루틴)이 실행된다.
    결과가 사용자 응용 프로그램에 반환된다.

핵심 포인트: 사용자 프로그램은 이름(open)으로 API를 호출하지만, 커널 내부에서는 번호(숫자)로 해당 시스템 콜 루틴을 찾는다. 사용자는 커널 내부의 세부 사항을 알 필요가 없다.

C 프로그램이 printf() 라이브러리 호출을 하면, 이 함수가 내부적으로 write() 시스템 콜을 호출한다.

[C 프로그램]
#include <stdio.h>
int main() {
printf("Greetings"); ← ① printf() 호출 (라이브러리 함수)
return 0;
}


[Standard C library] ← ② 표준 C 라이브러리 (사용자 모드)


[System call interface] ← ③ 시스템 콜 인터페이스 (경계)


[write() system call] ← ④ write() 시스템 콜 실행 (커널 모드)

  • printf()는 라이브러리 함수이다. 시스템 콜이 아니다.
  • printf() 내부에서 출력 데이터를 포맷한 후, 실제 화면 출력을 위해 write() 시스템 콜을 호출한다.
  • write()는 커널 모드에서 실행되어 실제 하드웨어(모니터)에 데이터를 전달한다.

핵심 포인트: 프로그래머가 사용하는 printf()는 사용자 공간의 라이브러리 함수이고, 실제 OS 서비스를 사용하는 것은 그 내부에서 호출되는 write() 시스템 콜이다. 이 계층 구조가 프로그래밍을 쉽게 만든다.

시스템 콜 구현 (System Call Implementation)

각 시스템 콜에는 시스템 콜 번호가 할당된다.

  • 시스템 콜에 연관된 커널 루틴은 메모리 내 테이블인 sys_call_table에서 해당 번호가 가리키는 항목에 정의된다.
  • 사용자 공간 프로세스가 시스템 콜을 실행할 때, 번호로 테이블에서 어떤 syscall이 실행되었는지 구분한다. 프로세스는 시스템 콜을 이름으로 참조하지 않는다.

실제 코드: sys_call_table (커널 측)

  • 이것은 커널 내부의 테이블로, 각 항목이 하나의 시스템 콜 커널 루틴(함수 포인터)이다. 배열 인덱스가 곧 시스템 콜 번호이다.

시스템 콜 번호 정의 (헤더 파일)

  • __NR_read는 3번 → sys_call_table[3]이 sys_read 함수를 가리킨다.
  • 새로운 시스템 콜 sys_foo를 추가하려면, 테이블에 항목을 추가하고(283번), 헤더 파일에 __NR_foo 283을 정의하면 된다.

핵심 포인트: 시스템 콜은 번호로 관리된다. 커널은 배열(sys_call_table)에서 번호를 인덱스로 사용하여 해당 커널 루틴의 주소를 찾아 실행한다.

사례 연구: Linux (Case Study: Linux)

시스템 콜 read를 살펴보자. (슬라이드 제목은 open이라 되어 있지만 실제 예시는 read이다.)

  • fd: 파일 디스크립터 (열린 파일을 식별하는 정수)
  • pBuf: 읽은 데이터를 저장할 버퍼의 포인터
  • nBytes: 읽을 바이트 수

시스템 콜은 매크로로 정의된다.

  • #define NR_read 3
    _syscall3(int,
    NR_read, int, fd, void*, pBuf, int, nBytes)
  • _syscall3은 인자가 3개인 시스템 콜을 위한 매크로이다.
    이 매크로는 내부적으로 인자를 레지스터에 넣고, 시스템 콜 번호(3)를 EAX에 넣은 뒤, int 0x80(소프트웨어 인터럽트)를 실행하는 어셈블리 코드를 생성한다.
// user 코드
syscall(5, "file.txt", 0);   // 5가 뭐지...?
syscall(2);                   // 2는 또 뭐고?
syscall(1, 0);                // ???
// user 코드
syscall(__NR_open, "file.txt", 0);  // 아, open이구나
syscall(__NR_fork);                  // fork
syscall(__NR_exit, 0);               // exit

시스템 콜 매개변수 전달 (System Call Parameter Passing)

OS에 매개변수를 전달하는 세 가지 일반적인 방법이 있다.

  • 방법 1: 레지스터 (Registers)

    • 가장 단순한 방법. 매개변수를 레지스터에 전달한다.
      장점: 매우 빠르다 (메모리 접근 불필요).
      단점: 레지스터 수가 제한되어 있어, 매개변수가 많으면 부족할 수 있다.
  • 방법 2: 블록/테이블 (Block or Table)

    • 매개변수를 메모리의 블록(테이블)에 저장하고, 그 블록의 주소를 레지스터로 전달한다.
      Linux와 Solaris가 이 방식을 사용한다.
  • 방법 3: 스택 (Stack)

    • 프로그램이 매개변수를 스택에 push하고, 운영체제가 스택에서 pop한다.
      Windows 계열이 이 방식을 사용한다.
      -> (수업에는 없음) Windows의 syscall 인자 전달 방식이 32비트 → 64비트 전환 시점에 완전히 바뀌었음

블록 방식과 스택 방식은 커널에 전달할 매개변수의 수나 길이를 제한하지 않는다.
레지스터 방식은 레지스터 수에 제한이 있지만, 블록/스택 방식은 메모리를 사용하므로 제한이 없다.

핵심 포인트: Linux는 블록(테이블) 방식, Windows는 스택 방식을 주로 사용한다. 두 방식 모두 매개변수 수에 제한이 없다는 장점이 있다.

  1. 사용자 프로그램이 매개변수를 메모리 블록 X에 저장한다.
  2. X의 주소를 레지스터에 넣는다.
  3. 시스템 콜 13을 호출한다.
  4. 커널은 레지스터에서 X의 주소를 가져와 테이블 X에서 매개변수를 읽어 사용한다.

Linux 시스템 콜 흐름 (Case Study: Linux)

read() 시스템 콜의 전체 흐름
이 그림은 read() 시스템 콜이 사용자 공간(User space)에서 커널 공간(Kernel space)까지 어떻게 흘러가는지 보여준다. 중앙의 빨간 선이 사용자 공간과 커널 공간의 경계이다.

단계위치동작한국어 설명
1main()push arguments, _libc_read()인자를 스택에 넣고 C 라이브러리의 read 함수 호출
2__libc_read()load args to regs, EAX = __NR_read인자를 레지스터에 로드, EAX에 시스템 콜 번호(3) 저장
3__libc_read()int 0x80소프트웨어 인터럽트(TRAP) 발생 → 커널 모드 진입
4system_call()SAVE_ALL, check EAX, syscall_tabEAX모든 레지스터 저장, EAX 범위 확인, 시스템 콜 테이블에서 해당 함수 호출
5sys_read()fget(fd), check file ops/locks파일 디스크립터로 파일 객체를 가져오고, 파일 연산과 락을 확인
6device coderetrieve data, copy data실제 장치에서 데이터를 가져와 사용자 버퍼에 복사
7system_call()handle signals, RESTORE_ALL, iret시그널 처리, 레지스터 복원, 인터럽트 리턴으로 사용자 모드 복귀
8__libc_read()check error, return에러 확인 후 결과 반환

Linux 시스템 콜의 핵심 메커니즘

  • 시스템 콜은 TRAP이라 불리는 소프트웨어 인터럽트로 구현되며, 커널 코드로 제어를 전달한다.
    Linux/i386에서는 인터럽트 0x80을 사용한다. 내부에서 일어나는 거 -> interrupt 아니고 별칭이다
  • 시스템 콜 번호는 EAX 레지스터에 저장되고, 인자는 프로세서 레지스터에 보관된다.
    read에 연관된 번호는 __NR_read이며, <asm/unistd.h> 헤더 파일에 정의되어 있다.

핵심 포인트: Linux에서 시스템 콜 호출의 핵심 흐름은 EAX에 번호 저장 → int 0x80으로 TRAP 발생 → 커널 진입 → sys_call_table에서 루틴 찾아 실행 → iret(interrupt return)으로 사용자 모드 복귀이다.

시스템 프로그램 (System Programs)



  • 시스템 프로그램은 프로그램 개발과 실행에 편리한 환경을 제공한다.
영어한국어설명 및 예시
File management파일 관리파일과 디렉토리의 생성, 삭제, 복사, 이름 변경, 출력, 덤프, 목록 조회 등
Status information상태 정보날짜, 시간, 사용 가능한 메모리, 디스크 공간, 사용자 수 등을 시스템에 질의. 성능, 로깅, 디버깅 정보도 제공. 일부 시스템은 **레지스트리(registry)**를 구현하여 설정 정보를 저장/조회
File traversal파일 탐색파일 내용을 검색하거나 텍스트 변환을 수행하는 특수 명령어 (예: grep, sed, awk)
Programming-language support프로그래밍 언어 지원컴파일러(compilers), 어셈블러(assemblers), 디버거(debuggers), 인터프리터(interpreters)
Program loading and execution프로그램 로딩 및 실행절대 로더, 재배치 로더, 링키지 에디터, 오버레이 로더, 고수준/기계어 디버깅 시스템
Communications통신프로세스, 사용자, 컴퓨터 시스템 간 가상 연결 메커니즘 제공. 예: 웹 페이지 브라우징, 이메일, 원격 로그인, 파일 전송
  • 시스템 프로그램은 시스템 콜이나 어셈블리 언어를 활용하여 개발된다.

핵심 포인트: 시스템 프로그램은 OS와 함께 제공되어 사용자가 파일 관리, 상태 조회, 프로그래밍, 통신 등의 작업을 쉽게 할 수 있도록 돕는다. 시스템 콜 위에 구축된 유틸리티 프로그램이다.

0개의 댓글