[Linux] 시스템 콜 정리

mommers·2026년 2월 2일

Linux

목록 보기
29/59

시스템 콜 (System call

사용자 공간(App)이 커널 공간(OS)의 기능을 빌려 쓰기 위한 '공식 요청 창구(API)'

리눅스는 '모든 것이 파일'이라는 철학에 따라, 하드웨어 제어(드라이버)도 파일 시스템 호출을 공유함


1. 정의 및 역할

사용자 어플리케이션이 운영체제(커널)의 자원이나 서비스를 요청하기 위해 커널 모드로 진입하는 관문. 시스템 콜 = 커널 API 라고도 부른다.(외부로 노출된 커널 함수).

  • 예시:
    read(), write()
    get_thread_area()
    set_tid_address()

2. 아키텍처별 호출 방식 (Software Interrupt)

CPU 아키텍처마다 커널 모드로 전환(Context Switch)하기 위한 어셈블리 명령어가 다릅니다.

아키텍처호출 명령어 (Trigger)비고
i386 (32bit)int 0x80레거시 인터럽트 방식
x86_64 (64bit)syscall고속 시스템 콜 전용 명령어 (약 300여 개 존재)
ARM / EABIswi 0x18Software Interrupt (또는 svc)

3. 동작 메커니즘 (Wrapper Routine)

개발자가 어셈블리(int 0x80 등)를 직접 짜지 않아도 되는 이유는 C 라이브러리(glibc)가 감싸주고 있기 때문입니다.

  • glibc (GNU C Library) 내부에 존재
  • 레지스터에 인자 값을 세팅하고 커널 진입 명령을 대신 실행함
    • 사용자 호출: open() (Wrapper Routine)
    • 실제 커널 함수: sys_open (System Call Handler)

4. 시스템 콜 분류 및 예시

관리 영역 (Subsystem)역할대표 시스템 콜
프로세스 관리프로세스 생성, 실행, 제어, 신호 처리fork(), execve(), getpid(), signal()
파일 시스템파일 열기, 읽기/쓰기, 닫기open(), read(), write(), close()
메모리 관리데이터 세그먼트 크기 변경 (힙 메모리 할당)brk(), sbrk()
네트워크소켓 통신 연결 및 데이터 전송socket(), bind(), connect(), listen(), accept()
디바이스 드라이버독자적인 시스템 콜 없음 (파일 시스템 콜을 빌려 씀)open, read, write, ioctl()(하드웨어 제어 핵심)

디바이스 드라이버

  • 특징: 리눅스에서 하드웨어 장치는 /dev/ 아래의 특수 파일(Device File)로 취급됩니다.
  • 동작: 따라서 별도의 드라이버 전용 함수 대신, 파일 시스템용 시스템 콜(open, read, write)을 그대로 사용하여 하드웨어를 제어합니다.
    • 예: LED를 켜기 위해 write() 사용, 센서 설정을 바꾸기 위해 ioctl() 사용.

하드웨어를 제어하는 소프트웨어를 디바이스 드라이버라고 한다.


System call wrapper 함수와 system call handler

Wrapper(요청 준비)Interrupt(커널 진입)Handler(실제 수행)Return(복귀) 의 순환 과정


1. 실행 흐름 4단계 (Step-by-Step)

① 사용자 모드 (User Space)

  • 호출: 응용 프로그램이 open(), read() 등 표준 함수 호출
  • Wrapper 루틴 (glibc):
    • CPU 레지스터에 인자 값과 시스템 콜 번호를 저장
    • 커널 모드로 전환하기 위한 트랩(Trap) 명령어 실행

② 모드 전환 (Context Switch)

  • 진입 (Entry):
    • Legacy (x86): int 0x80 (소프트웨어 인터럽트)
    • Modern (x86_64): sysenter 또는 syscall (고속 전용 명령)
  • CPU가 사용자 모드에서 커널 모드(Privileged Mode)로 권한 상승

③ 커널 모드 (Kernel Space)

  • System Call Handler:
    • 인터럽트를 감지하고 레지스터에 저장된 번호(Table Index)를 확인
  • Service Routine:
    • 실제 기능을 수행하는 커널 함수 실행 (예: sys_open, sys_read)

④ 복귀 (Return)

  • 종료 (Exit):
    • Legacy: iret (Interrupt Return)
    • Modern: sysexit 또는 sysret

swi : 소프트웨어 인터럽트


시스템 콜(System Call) 처리 과정–ARM

레지스터에 '주문 번호(Syscall No)'를 넣고 SVC 명령을 실행하면, CPU가 익셉션 벡터(Exception Vector)로 점프하여 커널 모드로 진입

x86의 int 0x80이나 syscall과 원리는 같으나, 사용하는 명령어와 레지스터가 다릅니다.

x86의 int 0x80이나 syscall과 원리는 같으나, 사용하는 명령어레지스터가 다릅니다.


1. 핵심 흐름 (Flow)

  1. 준비 (User): glibc 래퍼가 레지스터에 인자값과 시스템 콜 번호를 저장
  2. 발동 (Trigger): SVC (Supervisor Call) 명령어 실행 (구 SWI)
  3. 진입 (Exception): CPU가 User Mode → SVC Mode (또는 EL1)로 전환되고, 익셉션 벡터 테이블의 SVC 핸들러 주소로 점프
  4. 처리 (Kernel): 커널의 vector_swi(32bit) 또는 el0_svc(64bit) 루틴이 실행됨
  5. 복귀 (Return): 결과값을 레지스터에 싣고 유저 모드로 복귀

2. 아키텍처별 레지스터 규칙 (ABI)

개발자가 가장 신경 써야 할 "데이터 전달 약속"입니다.

구분ARM 32-bit (EABI)ARM 64-bit (AArch64)비고
명령어svc 0 (또는 swi)svc 0Supervisor Call
시스템 콜 번호R7X8"몇 번 함수 실행해줘?"
인자 (Args)R0 ~ R6X0 ~ X5함수 파라미터 전달
결과값 (Return)R0X0실행 결과 (성공/에러)
모드 전환User → SVC ModeEL0 → EL1Exception Level 상승

3. 단계별 상세 처리 (Deep Dive)

① Wrapper Routine (glibc)

  • 사용자가 open() 호출.
  • glibc 내부:
    • R0 = 파일 경로 포인터
    • R1 = 플래그 (Read/Write)
    • R7 = 5 (open의 시스템 콜 번호)
    • svc 0 실행!

② Exception Vector Table (H/W)

  • SVC 명령을 만나면 CPU는 하드웨어적으로 정해진 주소(Vector Base Address + Offset)로 강제 점프함.
  • 이곳에는 커널의 진입점(Entry Point) 코드가 있음.

③ Dispatcher (Kernel S/W)

  • 어셈블리 코드(entry-common.S)가 실행됨.
  • Context Save: 현재 유저 모드의 레지스터 값들을 스택(Kernel Stack)에 백업.
  • Table Lookup: sys_call_table에서 R7(또는 X8)에 해당하는 함수 주소를 찾음.
  • Execution: sys_open 함수 실행.

④ Return Path

  • sys_open이 파일 디스크립터(fd)를 반환.
  • 커널은 이 값을 R0(또는 X0)에 저장.
  • Context Restore: 스택에 백업해둔 유저 레지스터 복원.
  • movs pc, lr (32bit) 또는 eret (64bit) 명령어로 유저 모드 복귀.
profile
임베디드 개발자가 되기 위해 공부중입니다!

0개의 댓글