로더 (컴퓨팅)

컴퓨터 시스템에서 **로더**(loader)는 운영체제의 일부로, 프로그램과 라이브러리를 로드하는 역할을 한다. 프로그램 시작 과정에서 필수적인 단계 중 하나로, 프로그램을 메모리에 배치하고 실행을 준비한다. 프로그램을 로드하는 것은 프로그램 지침이 포함된 실행 파일의 내용을 메모리 맵하거나 메모리로 복사한 다음, 실행을 위해 실행 파일을 준비하는 데 필요한 다른 준비 작업을 수행하는 것을 포함한다. 로드가 완료되면 운영체제는 제어권을 로드된 프로그램 코드로 전달하여 프로그램을 시작한다.

고정된 특정 프로그램 세트만 있는 고도로 전문화된 컴퓨터 시스템을 제외하고, 프로그램 로드를 지원하는 모든 운영체제는 로더를 가지고 있다. 임베디드 시스템은 일반적으로 로더를 가지고 있지 않으며, 대신 코드가 ROM 또는 유사한 곳에서 직접 실행된다. 부팅의 일부로 운영체제 자체를 로드하기 위해서는 특수 부트 로더가 사용된다. 많은 운영체제에서 로더는 영구적으로 메모리에 상주하지만, 가상 메모리를 지원하는 일부 운영체제는 로더가 페이징 가능한 메모리 영역에 위치하도록 허용할 수 있다.

가상 메모리를 지원하는 운영체제의 경우, 로더가 실행 파일의 내용을 실제로 메모리에 복사하지 않고, 실행 중인 프로그램의 코드를 포함하도록 할당된 메모리 영역과 관련 실행 파일의 내용 사이에 매핑이 있음을 가상 메모리 서브시스템에 단순히 선언할 수 있다. (메모리 맵 파일 참조.) 그러면 가상 메모리 서브시스템은 프로그램 실행이 실제로 채워지지 않은 메모리 영역에 도달할 때 해당 메모리 영역의 페이지를 온디맨드로 채워야 한다는 것을 알게 된다. 이는 프로그램 코드의 일부가 실제로 사용될 때까지 메모리에 복사되지 않을 수 있으며, 사용되지 않는 코드는 전혀 메모리에 로드되지 않을 수 있음을 의미한다.
## 책임
유닉스에서 로더는 시스템 호출 `execve()`의 핸들러이다. 유닉스 로더의 작업은 다음과 같다.

# 유효성 검사 (권한, 메모리 요구 사항 등)
# 디스크의 실행 가능 개체를 메인 메모리로 메모리 매핑
# 명령줄 인수를 가상 메모리로 복사
# 레지스터 초기화 (예: 스택 포인터)
# 프로그램 진입점(`_start`)으로 점프

마이크로소프트 윈도우 7 이상에서 로더는 ntdll.dll에 포함된 `LdrInitializeThunk` 함수이며, 다음을 수행한다.

# DLL 자체의 구조 초기화 (예: 임계 구역, 모듈 목록)
# 로드할 실행 파일의 유효성 검사
# 힙 생성 (`RtlCreateHeap` 함수를 통해)
# 환경 변수 블록 및 PATH 블록 할당
# 모듈 목록(이중 연결 리스트)에 실행 파일 및 NTDLL 추가
# 여러 중요한 함수, 예를 들어 `BaseThreadInitThunk`를 얻기 위해 KERNEL32.DLL 로드
# 실행 파일의 임포트 (예: 동적 링크 라이브러리)를 재귀적으로 로드 (임포트의 임포트, 그 임포트 등을 확인)
# 디버그 모드에서 시스템 중단점 발생
# DLL 초기화
# 가비지 컬렉션
# 로더 함수에 주어진 컨텍스트 매개변수에서 `NtContinue` 호출 (즉, 실행 파일을 시작할 `RtlUserThreadStart`로 점프)

## 재배치 로더
일부 운영체제는 로딩이 시작되는 주소의 변화를 보상하기 위해 실행 파일의 주소(포인터)를 조정하는 재배치 로더를 필요로 한다. 재배치 로더가 필요한 운영체제는 프로그램이 (가상) 주소 공간의 항상 같은 위치에 로드되지 않고, 포인터가 프로그램의 기본 주소에 대한 오프셋이 아닌 절대 주소인 운영체제이다. 잘 알려진 예로는 IBM의 System/360 메인프레임용 OS/360과 Z/아키텍처 메인프레임용 Z/OS를 포함한 그 후손들이 있다.

### OS/360 및 파생 시스템
OS/360 및 파생 시스템에서 (특권) 운영체제 기능은 IEWFETCH라고 불리며, OS Supervisor의 내부 구성 요소이다. 반면 (비특권) LOADER 애플리케이션은 동일한 기능 중 많은 부분과 Linkage Editor의 기능을 수행할 수 있으며, OS Supervisor와는 완전히 외부적이다 (물론 많은 Supervisor 서비스를 사용하지만).

IEWFETCH는 고도로 전문화된 채널 프로그램을 활용하며, 이론적으로 DASD 미디어의 한 바퀴 회전(레거시 3,600rpm 드라이브에서 최대 약 16.6ms, 평균 8.3ms) 내에 전체 실행 파일을 로드하고 재배치하는 것이 가능하다. 트랙 크기를 초과하는 로드 모듈의 경우, 미디어의 회전을 잃지 않고 전체 모듈을 로드하고 재배치하는 것도 가능하다.

IEWFETCH는 또한 오버레이 구조를 위한 기능을 포함하고 있으며, 이는 최소 메모리 모델(OS의 일부 버전에서는 44KB만큼 작지만, 88KB 및 128KB가 더 흔함)에서 잠재적으로 매우 큰 실행 파일을 실행하는 것을 용이하게 한다.

OS의 핵심 (항상 상주하는 Supervisor 부분) 자체는 IEWFETCH의 간소화된 버전과 호환되는 방식으로 포맷된다. 일반적인 실행 파일과 달리 OS의 핵심은 "산발적으로 로드"된다. 즉, 핵심의 일부는 메모리의 다른 부분에 로드된다. 특히, 특정 시스템 테이블은 초기 64KB 미만에 상주해야 하며, 다른 테이블과 코드는 다른 곳에 상주할 수 있다.

시스템의 링크 편집기 애플리케이션은 IEWL이라고 불린다. IEWL의 주요 기능은 로드 모듈(실행 프로그램)과 목적 모듈(예: 어셈블러 및 컴파일러의 출력)을 라이브러리에 대한 "자동 호출"(고급 언어 "내장 함수")을 포함하여 IEWFETCH가 가장 효율적으로 로드할 수 있는 형식으로 연결하는 것이다. 많은 편집 옵션이 있지만, 일반적인 애플리케이션에서는 이 중 몇 가지만 일반적으로 사용된다.

로드 모듈 형식은 초기 "텍스트 레코드"로 시작하며, 즉시 해당 텍스트 레코드에 대한 "재배치 및 제어 레코드"가 뒤따르고, 모듈 끝까지 더 많은 텍스트 레코드와 재배치 및 제어 레코드 쌍이 이어진다.

텍스트 레코드는 일반적으로 매우 크다. 재배치 및 제어 레코드는 IEWFETCH의 세 가지 재배치 및 제어 레코드 버퍼가 260바이트로 고정되어 있으므로 작다 (더 작은 재배치 및 제어 레코드가 물론 가능하지만, 260바이트가 최대이며, IEWL은 필요한 경우 다음 텍스트 레코드 앞에 추가 재배치 레코드를 삽입하여 이 제한을 준수하도록 한다. 이 특별한 경우, 레코드의 순서는 ..., 텍스트 레코드, 재배치 레코드, ..., 제어 레코드, 텍스트 레코드, ...일 수 있다).

재배치 및 제어 레코드 버퍼 내의 특수 바이트는 "비활성화 비트 스핀" 통신 영역으로 사용되며 고유한 값으로 초기화된다. 해당 재배치 및 제어 레코드에 대한 Read CCW는 프로그램 제어 인터럽트 비트가 설정되어 있다. 따라서 프로세서는 특수 IOS 종료를 통해 채널에 의해 해당 CCW에 액세스되었을 때 알림을 받는다. 이 시점에서 프로세서는 "비활성화 비트 스핀" 루프(때로는 "세상에서 가장 짧은 루프"라고 불림)에 진입한다. 해당 바이트가 초기화된 값에서 변경되면 CPU는 비트 스핀을 종료하고, 재배치는 재배치 및 제어 레코드와 다음 텍스트 레코드 사이의 미디어 내 "틈" 동안 발생한다. 재배치가 다음 레코드 전에 완료되면 Read 뒤의 NOP CCW는 TIC로 변경되고, 다음 버퍼를 사용하여 로드 및 재배치가 진행된다. 그렇지 않으면 채널은 NOP CCW에서 멈추고, IEWFETCH에 의해 다른 특수 IOS 종료를 통해 다시 시작될 때까지 기다린다. 세 개의 버퍼는 연속적인 원형 큐에 있으며, 각각 다음을 가리키고 마지막은 첫 번째를 가리키며, 로드 및 재배치가 진행됨에 따라 세 개의 버퍼가 계속 재사용된다.

따라서 IEWFETCH는 실용적인 크기의 로드 모듈을 가능한 최소 시간 내에 로드하고 재배치할 수 있다.
## 동적 링커
동적 연결 로더는 공유 라이브러리(.so 파일, .dll 파일 또는 .dylib 파일과 같은)를 이미 로드된 실행 중인 프로그램에 로드하고 연결하는 또 다른 유형의 로더이다.

이러한 공유 라이브러리가 여러 프로세스에서 공유될 수 있고, 공유 코드의 단일 복사본이 각 프로세스의 주소 공간에서 다른 (가상) 주소에 나타날 수 있는 경우, 공유 라이브러리의 코드는 재배치 가능해야 한다. 즉, 라이브러리는 전체적으로 자체 상대 주소 또는 코드 세그먼트 기준 상대 내부 주소만 사용해야 한다. 일부 프로세서는 이를 용이하게 하기 위해 자체 상대 코드 참조를 사용할 수 있는 명령을 가지고 있다.

## 같이 보기
* DLL 지옥
* 동적 디스패치
* 동적 링커
* 동적 링크 라이브러리
* 링커 (컴퓨팅)
* 라이브러리 (컴퓨팅)
* 링커 (컴퓨팅)
* 네임 맹글링
* 셔뱅
* 정적 라이브러리

## 각주

분류:라이브러리
분류:운영체제 커널