Devendency

person
시스템콜

시스템콜

OS를 deep 하게 공부할때 선행하면 좋은 개념이다.


시스템 콜은 운영체제의 커널이 제공하는 서비스를 사용자 프로그램이 이용하기 위한 유일한 통로

사용자 모드에서 실행되는 프로그램이 파일 입출력, 프로세스 생성 등 특권 명령이 필요한 작업을 수행해야 할 때, 커널 모드로 전환하여 OS에게 해당 작업을 요청하는 방법

목적 : OS 자원에 대한 직접적인 접근을 제한하여 시스템의 안정성보호를 유지

응용 프로그래밍 인터페이스와 시스템 콜

프로그래머가 시스템 콜을 직접 호출하는 경우는 드물다. 대신 API(Application Programming Interface) 를 통해 접근한다.

시스템 콜

  • 커널에게 서비스를 요청하는 실제 인터페이스
  • 커널 내부에 존재
  • 하나의 API 함수가 하나 이상의 시스템 콜을 호출할 수 있다

API

  • 프로그래머가 시스템 콜에 접근하기 위해 사용하는 함수들의 집합
  • 사용자 모드 라이브러리에 존재
  • 대표적인 API 3가지:
    • Windows API (Win32/Win64) : Windows 시스템용
    • POSIX API : Unix/Linux/macOS 공통 표준
    • Java API : JVM 기반, 플랫폼 독립적

동작과정

  1. 준비 (Preparation):
    • 사용자 프로그램이 API(예: read())를 호출하면, 라이브러리는 해당 요청에 맞는 시스템 콜 번호를 특정 레지스터에 넣음
    • 추가적인 매개변수(파일 이름, 버퍼 주소 등)도 전달해야 하는데, 전달 방식은 3가지가 있다:
      • 레지스터에 직접 전달 : 가장 단순하지만 레지스터 수보다 매개변수가 많으면 불가능
      • 메모리 블록(테이블)에 저장 : 매개변수를 메모리에 넣고 시작 주소만 레지스터에 전달
      • 스택에 push : 매개변수를 스택에 push하고 OS가 pop하여 가져감
  2. 트랩 발생 (The Trap):
    • trap이나 syscall 명령을 실행. 이 순간 하드웨어가 실행 모드를 사용자 모드(1)에서 커널 모드(0)로 즉시 전환
  3. 커널 서비스 실행 (Kernel Execution):
    • 커널은 레지스터에 저장된 시스템 콜 번호를 읽어 시스템 콜 테이블에서 실행할 루틴을 찾음
    • 시스템 콜 테이블은 시스템 콜 번호를 인덱스로 사용하여 해당 서비스 루틴의 주소를 찾는 구조
    • 매개변수의 유효성을 검사한 뒤 작업을 수행
  4. 결과 반환 및 복귀 (Return):
    • 작업 결과나 상태 코드를 특정 레지스터에 저장
    • 'Return from interrupt' 명령을 통해 모드 비트를 1(사용자 모드)로 되돌리고, 시스템 콜 바로 다음 지점부터 프로그램을 재개

시스템 콜에서 자주 쓰이는 용어

  • fd (File Descriptor) : 열린 파일이나 장치를 가리키는 정수 번호. open()이 반환하고, read/write/close 등이 이 번호로 대상을 식별한다
    • 0 = stdin(표준 입력), 1 = stdout(표준 출력), 2 = stderr(표준 에러)
    • 새로 열면 3부터 순서대로 배정
ls -l /proc/$$/fd    # 현재 프로세스의 fd 목록 확인
  • buf (Buffer) : 데이터를 임시로 담아두는 메모리 공간. read()는 파일에서 읽은 데이터를 buf에 저장하고, write()는 buf의 데이터를 파일에 쓴다
  • path : 파일이나 디렉토리의 경로. open("/etc/hostname")처럼 대상을 지정할 때 사용
    • 절대 경로: /etc/hostname (루트부터 전체 경로)
    • 상대 경로: ./test.txt (현재 위치 기준)
  • pid (Process ID) : 프로세스를 식별하는 고유 정수. fork()가 자식의 pid를 반환하고, kill(pid)로 특정 프로세스에 신호를 보냄다
  • mode : 파일의 접근 권한을 나타내는 값. chmod(path, 0755)처럼 8진수로 표현
    • r=4, w=2, x=1 → rwx=7, r-x=5, r--=4
  • offset : 파일 내에서 읽기/쓰기 위치를 나타내는 바이트 단위 값. lseek(fd, offset)로 위치를 이동
  • size / count : 읽거나 쓸 데이터의 크기(바이트 수). read(fd, buf, 1024)면 최대 1024바이트 읽기
  • flags : 동작 모드를 지정하는 옵션 값. open()에서 사용
    • O_RDONLY(읽기전용), O_WRONLY(쓰기전용), O_RDWR(읽기+쓰기)
    • O_CREAT(없으면 생성), O_APPEND(끝에 추가), O_TRUNC(기존 내용 지우고 열기)
  • sig (Signal) : 프로세스에 보내는 신호. kill(pid, sig)로 전송
    • SIGTERM(15) = 정상 종료 요청, SIGKILL(9) = 강제 종료, SIGINT(2) = Ctrl+C

시스템 콜 인자 레퍼런스

프로세스 제어

  • fork() — 인자: 없음 / 반환: 부모에게 자식 pid, 자식에게 0, 실패 시 -1
  • exec(path, args) — path: 실행할 프로그램 경로 ("/bin/ls"), args: 인자 배열 (["ls", "-la"])
  • exit(status) — status: 종료 상태 코드. 0이면 정상, 0 외이면 오류
  • wait(status) — status: 자식의 종료 상태를 저장할 포인터 / 반환: 종료된 자식의 pid
  • abort() — 인자: 없음. 호출 시 현재 프로세스에 SIGABRT 전송
  • getpid() — 인자: 없음 / 반환: 현재 프로세스의 pid
  • kill(pid, sig) — pid: 대상 프로세스 ID, sig: 보낼 신호 번호 (9=SIGKILL, 15=SIGTERM)

파일 관리

  • open(path, flags, mode) — path: 파일 경로, flags: 열기 모드(O_RDONLY 등), mode: 생성 시 권한(0644) / 반환: fd, 실패 시 -1
  • close(fd) — fd: 닫을 파일 디스크립터
  • read(fd, buf, count) — fd: 읽을 대상, buf: 데이터 저장할 버퍼, count: 읽을 최대 바이트 수 / 반환: 실제 읽은 바이트 수
  • write(fd, buf, count) — fd: 쓸 대상, buf: 쓸 데이터가 담긴 버퍼, count: 쓸 바이트 수 / 반환: 실제 쓴 바이트 수
  • lseek(fd, offset, whence) — fd: 대상 파일, offset: 이동할 바이트 수, whence: 기준점 (SEEK_SET=파일 시작, SEEK_CUR=현재 위치, SEEK_END=파일 끝)
  • unlink(path) — path: 제거할 파일 경로

장치 관리

  • ioctl(fd, request, arg) — fd: 장치 fd, request: 장치별 제어 명령 번호, arg: 명령에 전달할 인자

정보 유지

  • time(t) — t: 시간을 저장할 포인터 (NULL 가능) / 반환: 유닉스 타임스탬프 (초)
  • gettimeofday(tv, tz) — tv: 시간을 저장할 구조체 (초 + 마이크로초), tz: 타임존 (NULL 가능)

통신

  • pipe(fd[2]) — fd[2]: 파이프의 읽기(fd[0])/쓰기(fd[1]) 끝을 담을 배열
  • shm_open(name, flags, mode) — name: 공유 메모리 이름 ("/my_shm"), flags: 열기 모드, mode: 권한
  • mmap(addr, length, prot, flags, fd, offset) — addr: 매핑 시작 주소(NULL이면 OS가 결정), length: 매핑 크기, prot: 보호 모드(PROT_READ/WRITE), flags: 매핑 옵션(MAP_SHARED 등), fd: 대상 파일/공유메모리, offset: 시작 오프셋
  • munmap(addr, length) — addr: 해제할 매핑 시작 주소, length: 해제할 크기
  • socket(domain, type, protocol) — domain: 주소 체계(AF_INET=IPv4, AF_INET6=IPv6, AF_UNIX=로컬), type: 소켓 유형(SOCK_STREAM=TCP, SOCK_DGRAM=UDP), protocol: 보통 0
  • send(fd, buf, len, flags) — fd: 소켓 fd, buf: 보낼 데이터, len: 데이터 크기, flags: 옵션(0이면 기본)
  • recv(fd, buf, len, flags) — fd: 소켓 fd, buf: 받을 버퍼, len: 버퍼 크기, flags: 옵션

보호

  • chmod(path, mode) — path: 대상 파일 경로, mode: 설정할 권한 (0755 등)
  • chown(path, owner, group) — path: 대상, owner: 새 소유자 UID, group: 새 그룹 GID
  • umask(mask) — mask: 새 파일 생성 시 제거할 권한 마스크 (0022 등) / 반환: 이전 umask 값
  • setuid(uid) — uid: 설정할 유효 사용자 ID
  • setgid(gid) — gid: 설정할 유효 그룹 ID

시스템 콜 유형

프로세스 제어

  • 프로세스의 생성, 실행, 종료, 일시 정지 등 생명주기를 관리
  • fork() : 현재 프로세스를 복제하여 자식 프로세스를 생성. 부모에게는 자식 PID를, 자식에게는 0을 반환
strace -f -e fork bash -c "ls"   # fork 시스템콜 추적
ps -ef | grep bash               # bash 프로세스와 자식 확인
  • exec() : 현재 프로세스의 메모리를 새로운 프로그램으로 교체하여 실행. fork() 후 자식에서 호출하는 패턴이 일반적
exec top   # 현재 쉘이 top으로 대체됨 (돌아오지 않음)
  • exit() : 현재 프로세스를 정상 종료. OS에 종료 상태 값을 반환
exit 0     # 정상 종료 (상태코드 0)
exit 1     # 오류로 종료
echo $?    # 직전 명령어의 종료 상태코드 확인
  • wait() : 부모 프로세스가 자식 프로세스의 종료를 기다림
sleep 5 &        # 백그라운드로 5초 대기
wait $!          # 방금 실행한 백그라운드 프로세스 종료 대기
echo "done"
  • abort() : 프로세스를 비정상 강제 종료
kill -SIGABRT 1234   # PID 1234에 SIGABRT 전송
kill -9 1234         # SIGKILL로 무조건 강제 종료
  • getpid() : 현재 프로세스의 PID(프로세스 ID)를 반환
echo $$          # 현재 쉘의 PID
echo $PPID       # 부모 프로세스의 PID

파일 관리

  • 파일의 생성, 삭제, 열기, 닫기, 읽기, 쓰기 등 파일 시스템 관련 작업을 관리
  • open() : 파일을 열고 파일 디스크립터(fd)를 반환
exec 3< /etc/hostname   # fd 3으로 파일 열기
cat <&3                 # fd 3에서 읽기
exec 3<&-               # fd 3 닫기
ls -l /proc/$$/fd       # 현재 프로세스의 열린 fd 목록
  • close() : 열린 파일 디스크립터를 닫음. 자원 해제
  • read() : 파일에서 데이터를 읽어 버퍼에 저장
  • write() : 버퍼의 데이터를 파일에 쓰기
cat /etc/hostname          # 내부적으로 open+read+write+close
echo "hello" > test.txt    # open(O_WRONLY|O_CREAT) + write + close
echo "world" >> test.txt   # open(O_APPEND) + write + close
  • lseek() : 파일 내 읽기/쓰기 위치(오프셋)를 이동
dd if=/etc/hostname bs=1 skip=3 count=5   # 3바이트 건너뛰고 5바이트 읽기
  • unlink() : 파일의 링크를 제거. 링크가 0이 되면 파일 삭제
rm test.txt         # 내부적으로 unlink() 호출
unlink test.txt     # 직접 unlink 명령어

장치 관리

  • I/O 장치의 요청, 해제, 제어 등을 관리
  • ioctl() : 장치별 고유한 제어 명령을 전달
ethtool eth0           # 네트워크 카드 상태/속도 (ioctl 기반)
hdparm -I /dev/sda     # 디스크 장치 정보
  • read() / write() : 장치를 대상으로 데이터를 읽거나 쓰기 (파일과 동일한 인터페이스)
cat /dev/urandom | head -c 16 | xxd   # 랜덤 장치에서 16바이트 읽기
echo "test" > /dev/null               # null 장치에 쓰기 (버려짐)
  • request() : 장치 사용을 OS에 요청
  • release() : 장치 사용을 해제
mount /dev/sdb1 /mnt/usb     # 장치 요청 + 파일시스템 연결
umount /mnt/usb              # 장치 해제

정보 유지 관리

  • 시스템 시간, 날짜, 프로세스 정보 등 시스템 상태 정보를 얻거나 설정
  • getpid() : 현재 프로세스의 PID 반환
  • time() : 1970년 1월 1일부터 경과한 초(유닉스 타임스탬프)를 반환
  • gettimeofday() : 현재 시간을 마이크로초 단위까지 반환
  • uname() : 시스템 정보(커널 버전, 호스트명 등)를 반환
date                 # 현재 날짜/시간 (time/gettimeofday)
date +%s             # 유닉스 타임스탬프
uname -a             # 커널 버전, 호스트명, 아키텍처 전체
uname -r             # 커널 버전만
uptime               # 시스템 가동 시간

통신

  • 프로세스 간 통신을 위한 연결 생성, 메시지 송수신 등을 관리
  • pipe() : 부모-자식 프로세스 간 단방향 통신 채널 생성
ls -la | grep ".txt"                   # ls stdout → grep stdin
ps aux | sort -k 3 -rn | head -5       # CPU 상위 5개
  • shm_open() : 공유 메모리 객체를 생성/열기
  • mmap() : 파일이나 공유 메모리를 프로세스 주소 공간에 매핑
  • munmap() : mmap()으로 매핑된 영역을 해제
ls -la /dev/shm/         # 공유 메모리 객체 목록
ipcs -m                  # System V 공유 메모리 확인
  • socket() : 네트워크 통신 끝점(소켓) 생성
  • send() : 소켓으로 데이터 전송
  • recv() : 소켓으로 데이터 수신
nc -l 8080               # 서버: 8080 대기 (socket+bind+listen+accept)
nc localhost 8080        # 클라이언트: 연결 (socket+connect)
# 연결 후 텍스트 입력 → 상대방에게 전송 (send/recv)
ss -tlnp                 # 열린 TCP 소켓 확인
ss -ulnp                 # 열린 UDP 소켓 확인

보호

  • 자원 접근 권한 관리
  • chmod() : 파일/디렉토리의 접근 권한(rwx)을 변경
chmod 755 script.sh        # 소유자 rwx, 그룹/기타 r-x
chmod u+x script.sh        # 소유자에게 실행 권한 추가
chmod -R 644 /var/www      # 하위 전체 재귀적 적용
  • umask() : 새 파일의 기본 권한 마스크 지정
umask                      # 현재 umask 값 확인 (보통 0022)
umask 0027                 # 새 파일: 640, 새 디렉토리: 750
  • chown() : 파일 소유자(owner)와 그룹(group) 변경
chown bob:developers file.txt       # 소유자 bob, 그룹 developers
chown -R www-data:www-data /var/www # 웹 디렉토리 전체
  • setuid() : 프로세스의 유효 사용자 ID(EUID) 변경. 임시 권한 상승
  • setgid() : 프로세스의 유효 그룹 ID(EGID) 변경
find / -perm -4000 -type f 2>/dev/null   # SUID 설정된 파일 찾기
ls -la /usr/bin/passwd   # -rwsr-xr-x (s = SUID)
sudo command             # 임시 root 권한 상승 (내부적으로 setuid)
id                       # 현재 UID, GID, EUID 확인

댓글 0