시스템 프로그래밍이란 커널 및 핵심 시스템 라이브러리를 직접 사용하면서 하위 레벨에서 동작하는 시스템 소프트웨어를 작성하는 기술을 말합니다. 시스템 소프트웨어의 예로는 shell, vim, gcc 등이 있습니다. 그 외에도 네트워크 서버, 웹 서버, 데이터베이스 또한 시스템 소프트웨어 중 하나이며 이런 소프트웨어는 커널과 C 라이브러리를 직접 사용합니다.
시스템 프로그램과 애플리케이션 프로그램의 구분을 사용자 입장에서 해봅시다. 프로그램은 시스템 프로그램과 애플리케이션 프로그램으로 나눌 수 있습니다. 사용자의 눈에 보이고 손에 닿는 것은 애플리케이션 프로그램으로 반대로 눈에 보이지 않고 손에 닿지 않는 것은 시스템 프로그램으로 구분할 수 있습니다. 이는 완벽히 맞는 설명은 아니지만 직관적이며 대부분의 경우 옳다고 할 수 있습니다.
앞의 설명보다 상대적으로 정확한 구분은 다음과 같습니다. 두 프로그램은 중요한 몇몇 부분을 제외하고 나머지는 비슷하다고 할 수 있습니다. 시스템 프로그램은 커널 및 핵심 시스템 라이브러리(시스템 콜)를 많이 사용하고 애플리케이션 프로그램은 비교적 고급 라이브러리를 많이 사용하는 것으로 그 차이를 둘 수 있습니다.
유닉스가 탄생한 이후 지난 수십년 간 프로그래밍의 무게추는 시스템 프로그래밍에서 자바스크립트의 웹 소프트웨어나 그 외 다른 상위 래벨로 이동하고 있습니다. 그러나 지금도 누군가는 하위 레벨의 gcc, interpreter등을 개발하고 있습니다. 게다가 python, ruby 등의 프로그램도 시스템 프로그래밍을 이해한 상태에서 작성한다면 더 나은 성능을 보입니다. 그리고 컴퓨터 공학의 이해를 돕는 유닉스와 리눅스의 코드 대부분은 시스템 래벨에서 작성됩니다. 애플리케이션 프로그램의 성능 향상을 위해서라도 컴퓨터 공학의 근간을 위해서라도 시스템 프로그래밍에 대한 연구와 학습은 계속되어야 합니다.
시스템 프로그래밍에서 시스템 콜은 핵심입니다. "시스템 콜은 운영체제에 리소스나 서비스를 요청하려고 사용자 영역에서 시작해서 커널 내부로 들어가는 함수 호출이기 때문입니다." - 로버트 러버, 리눅스 시스템 프로그래밍(한빛 미디어, 2017), 32p.
사용자의 영역에서 애플리케이션을 커널 영역으로 직접 연결하는 것은 불가능합니다. 보안과 안정성의 이유로 애플리케이션은 커널 코드를 직접 실행하거나 커널 내부 데이터를 조작할 수 없습니다. 대신, 애플리케이션이 시스템 콜을 실행하려고 한다는 '시그널'을 커널로 보낼 수 있다. 시스템 콜을 부르는 시그널을 사용해야 커널 내부로 진입하고 커널이 허용한 코드를 실행할 수 있습니다.
애플리케이션은 사용하고자하는 시스템 콜과 매개 변수를 레지스터를 통해 전달합니다. 그리고 시스템 콜을 0부터 시작하는 숫자로 나타내며 이런 시스템 콜을 시그널을 통해 호출하려면 레지스터에 해당 시스템 콜을 먼저 저장해야 합니다. "예를 들어 i386 아키텍처에서 시스템 콜 5번 (open())을 호출하려면 응용 프로그램 int명령을 실행하기 전에 eax 레지스터에 5를 저장해야 한다." - 로버트 러버, 리눅스 시스템 프로그래밍(한빛 미디어, 2017), 34p.
아키텍처별로 시스템 콜을 처리하는 방식은 다르지만, 기본 원리는 같습니다. 그리고 커널이 시스템 콜을 처리하는 방식은 아키텍처의 표준 콜린 컨벤션(standard calling convention)에 녹아 있으며 컴파일러와 C 라이브러리에서 자동으로 처리된다.
C 표준 라이브러리는 매크로, 타입 정의 그리고 문자열 처리나 수학적 연산, 입출력 프로세스, 메모리 할당과 다른 운영 체제 서비스 같은 작업을 위한 함수들을 제공한다. 그리고 C 라이브러리는 시스템 프로그래밍의 핵심입니다. 리눅스 혹은 유닉스에서 핵심 서비스와 시스템 콜을 처리하기 위해 C 라이브러리가 동작하고 있습니다. 최신 리눅스 시스템에서는 GNU C 라이브러리인 glibc가 제공되고 있습니다. 그리고 glibc 라이브러리는 ISO C11, POSIX.1-2008, BSD, OS별 API 등을 포함한 중요한 API를 제공하고 있습니다.
컴파일이란 어떤 언어의 코드 전체를 다른 언어로 바꿔주는 과정입니다. 그리고 이것을 자동으로 수행해주는 소프트웨어를 컴파일러라고 합니다. 시스템 프로그래밍의 핵심 언어인 C를 위해 리눅스는 표준 C 컴파일러로 GNU 컴파일러 컬랙션(GCC)을 제공합니다. GCC는 초기에는 C만 지원했지만 시간이 흘러 여러 가지 언어를 지원하게 되었고 그 결과 현재 GCC는 GNU 컴파일러군을 아우르는 일반적인 이름이 되었습니다.