동적 링크 라이브러리

**동적 링크 라이브러리**(, **DLL**)는 마이크로소프트 윈도우 또는 OS/2 운영체제의 공유 라이브러리이다. DLL에는 실행 코드(함수), 데이터 및 리소스가 포함될 수 있다.

DLL 파일은 일반적으로 파일 확장자 `.dll`을 사용하지만 필수는 아니다. 이 확장자는 때때로 파일의 내용을 설명하는 데 사용된다. 예를 들어, `.ocx`는 ActiveX 컨트롤에 대한 일반적인 확장자이며 `.drv`는 레거시(16비트) 장치 드라이버에 대한 확장자이다.

리소스만 포함하는 DLL은 리소스 DLL이라고 불릴 수 있다. 예시로는 일반 확장자 `.icl`을 가진 아이콘 라이브러리, 그리고 일반 확장자 `.fon` 및 `.fot`을 가진 글꼴 라이브러리가 있다.

DLL의 파일 형식은 실행 파일(일명 EXE)과 동일하다. DLL 파일과 EXE 파일의 주요 차이점은 운영 체제가 실행을 시작하기 위해 엔트리 포인트를 요구하기 때문에 DLL을 직접 실행할 수 없다는 점이다. 윈도우는 DLL이 노출하는 함수를 실행하기 위한 유틸리티 프로그램(RUNDLL.EXE/RUNDLL32.EXE)을 제공한다. 동일한 형식을 가지므로 EXE도 DLL로 사용될 수 있다. 소비 코드는 DLL을 로드하는 것과 동일한 메커니즘을 통해 EXE를 로드할 수 있다.

## 배경
마이크로소프트 윈도우의 초기 버전은 단일 주소 공간에서 프로그램을 함께 실행했다. 모든 프로그램은 그래픽 사용자 인터페이스(GUI)가 멀티태스킹하고 최대한 응답할 수 있도록 CPU를 다른 프로그램에 양보하여 협력하도록 되어 있었다. 모든 운영 체제 수준 작업은 기본 운영 체제인 MS-DOS에 의해 제공되었다. 모든 상위 수준 서비스는 윈도우 라이브러리 "동적 링크 라이브러리"에 의해 제공되었다. 드로잉 API, 그래픽 장치 인터페이스(GDI)는 `GDI.EXE`라는 DLL에 구현되었고, 사용자 인터페이스는 `USER.EXE`에 구현되었다. DOS 위에 있는 이러한 추가 레이어는 1메가바이트 미만의 RAM을 가진 컴퓨터에서 윈도우가 작동할 수 있도록 할 뿐만 아니라 프로그램들이 서로 협력할 수 있도록 모든 실행 중인 윈도우 프로그램에서 공유되어야 했다. GDI의 코드는 드로잉 명령을 특정 장치에서의 작업으로 변환해야 했다. 디스플레이에서는 프레임 버퍼의 픽셀을 조작해야 했다. 프린터에 그릴 때는 API 호출이 프린터 요청으로 변환되어야 했다. 제한된 장치 세트(예: 컬러 그래픽스 어댑터 디스플레이, HP 레이저젯 프린터 명령 언어)에 대한 하드코딩된 지원을 제공할 수 있었지만, 마이크로소프트는 다른 접근 방식을 선택했다. GDI는 "장치 드라이버"라고 불리는 다른 코드 조각을 로드하여 다른 출력 장치와 작동하도록 했다.

GDI가 다른 장치 드라이버를 로드할 수 있게 한 동일한 아키텍처 개념은 윈도우 셸이 다른 윈도우 프로그램을 로드하고, 이러한 프로그램들이 공유 USER 및 GDI 라이브러리에서 API 호출을 호출할 수 있게 했다. 그 개념이 바로 "동적 링크"였다.

기존의 비공유 정적 라이브러리에서는 코딩 단계에서 실행 파일이 빌드될 때 호출 프로그램에 코드 섹션이 단순히 추가된다. 두 프로그램이 동일한 루틴을 호출하는 경우, 해당 루틴은 두 프로그램의 링크 단계에서 모두 포함된다. 동적 링크에서는 공유 코드가 단일의 별도 파일에 배치된다. 이 파일을 호출하는 프로그램은 런타임에 운영 체제(또는 윈도우 초기 버전의 경우 OS 확장)가 바인딩을 수행하면서 연결된다.

초기 버전의 윈도우(1.0 ~ 3.11)의 경우 DLL은 전체 GUI의 기반이 되었다. 따라서 디스플레이 드라이버는 단순히 .DRV 확장자를 가진 DLL로, 통합된 장치 드라이버 인터페이스(DDI)를 통해 동일한 드로잉 API의 사용자 지정 구현을 제공했으며, 드로잉(GDI) 및 GUI(USER) API는 단순히 .EXE 확장자를 가진 GDI 및 USER 시스템 DLL이 내보내는 함수 호출이었다.

동적으로 로드되는 라이브러리 컬렉션에서 운영 체제를 구축하는 이 개념은 윈도우의 핵심 개념이며  현재까지 유지되고 있다.
DLL은 공유 라이브러리의 표준 이점인 모듈화를 제공한다. 모듈화를 통해 여러 애플리케이션에서 공유되는 단일 자체 포함 DLL의 코드와 데이터를 애플리케이션 자체를 변경하지 않고도 변경할 수 있다.

모듈화의 또 다른 이점은 플러그인을 위한 일반 인터페이스를 사용하는 것이다. 애플리케이션 자체를 수정하지 않고도 기존 애플리케이션에 이전 모듈과 새로운 모듈을 런타임에 원활하게 통합할 수 있는 단일 인터페이스가 개발될 수 있다. 이러한 동적 확장성 개념은 액티브X의 기반이 되는 컴포넌트 오브젝트 모델에서 극대화된다.

윈도우 1.x, 2.x, 3.x에서는 모든 윈도우 응용 프로그램이 동일한 주소 공간과 메모리를 공유했다. DLL은 이 주소 공간에 한 번만 로드되었으며, 그 이후로는 라이브러리를 사용하는 모든 프로그램이 DLL에 액세스했다. 라이브러리의 데이터는 모든 프로그램에서 공유되었다. 이는 간접적인 형태의 프로세스 간 통신으로 사용될 수도 있었고, 의도치 않게 다른 프로그램을 손상시킬 수도 있었다. 윈도우 95에서 32비트 라이브러리가 도입되면서 각 프로세스는 자체 주소 공간에서 실행되었다. DLL 코드는 공유될 수 있지만, 공유 데이터가 라이브러리에 의해 명시적으로 요청되지 않는 한 데이터는 비공개이다. 그러나 윈도우 95, 윈도우 98, 윈도우 미의 상당 부분은 16비트 라이브러리로 구축되었으며, 이는 출시 당시 펜티엄 프로 마이크로프로세서의 성능을 제한하고 궁극적으로 DOS 기반 윈도우 버전의 안정성과 확장성을 제한했다.

## 한계

DLL 기술은 윈도우 아키텍처의 핵심이지만 단점도 있다.

### DLL 지옥

DLL 지옥은 잘못된 버전의 DLL이 사용될 때 애플리케이션이 비정상적으로 동작하는 것을 설명한다. 완화 전략은 다음과 같다.
* 닷넷 프레임워크
* 마이크로소프트 버추얼 PC 및 마이크로소프트 애플리케이션 가상화와 같은 가상화 기반 솔루션은 애플리케이션 간의 격리를 제공한다.
* 사이드 바이 사이드 어셈블리

### 공유 메모리 공간

DLL의 실행 코드는 호출 프로세스의 메모리 공간에서 동일한 접근 권한으로 실행된다. 이는 사용 시 오버헤드가 적다는 것을 의미하지만, DLL에 어떤 종류의 버그가 있을 경우 호출 프로그램에 대한 보호가 거의 없다는 것을 의미하기도 한다.

## 특징

### 업그레이드 가능성
DLL 기술은 소비 구성 요소를 다시 컴파일하거나 다시 링크할 필요 없이 애플리케이션을 수정할 수 있도록 한다. DLL을 교체하면 다음번에 애플리케이션을 실행할 때 새로운 DLL 버전을 사용한다. 올바르게 작동하려면 DLL 변경 사항이 하위 호환성을 유지해야 한다.

운영 체제도 DLL을 통해 애플리케이션에 노출되기 때문에 업그레이드할 수 있다. 시스템 DLL을 교체하면 다음번에 애플리케이션을 실행할 때 새로운 시스템 DLL을 사용한다.

### 메모리 관리
윈도우 API에서 DLL 파일은 섹션으로 구성된다. 각 섹션은 쓰기 가능 또는 읽기 전용, 실행 가능(코드용) 또는 비실행 가능(데이터용) 등 자체 속성 집합을 갖는다.

DLL의 코드는 일반적으로 DLL을 사용하는 모든 프로세스 간에 공유된다. 즉, 물리적 메모리의 한 곳을 차지하며, 페이지 파일의 공간을 차지하지 않는다. 윈도우는 DLL에 대해 위치 독립 코드를 사용하지 않는다. 대신, 코드는 로드될 때 재배치되어 DLL을 로드하는 첫 번째 프로세스의 메모리 공간에서 사용 가능한 위치에 모든 진입점의 주소를 고정한다. 모든 실행 중인 프로세스가 단일 공통 주소 공간을 차지했던 이전 버전의 윈도우에서는 DLL 코드의 단일 복사본이 모든 프로세스에 항상 충분했다. 그러나 각 프로그램에 대해 별도의 주소 공간을 사용하는 최신 버전의 윈도우에서는 각 프로그램이 DLL 코드를 수용할 수 있는 동일한 가상 주소를 가지고 있는 경우에만 여러 프로그램에서 동일한 재배치된 DLL 복사본을 사용할 수 있다. 일부 프로그램(또는 이미 로드된 DLL의 조합)에 해당 주소가 비어 있지 않으면, 다른 재배치된 진입점 세트를 사용하여 DLL 코드의 추가 물리적 복사본을 생성해야 한다. 코드 섹션이 차지하는 물리적 메모리를 회수해야 하는 경우, 해당 내용은 버려지고 필요할 때 DLL 파일에서 직접 다시 로드된다.

코드 섹션과 달리 DLL의 데이터 섹션은 일반적으로 비공개이다. 즉, DLL을 사용하는 각 프로세스는 DLL의 모든 데이터의 자체 사본을 갖는다. 선택적으로 데이터 섹션을 공유하여 이 공유 메모리 영역을 통해 프로세스 간 통신을 허용할 수 있다. 그러나 사용자 제한이 공유 DLL 메모리 사용에 적용되지 않으므로, 이는 보안 허점을 생성한다. 즉, 한 프로세스가 공유 데이터를 손상시킬 수 있으며, 이는 다른 모든 공유 프로세스가 원치 않는 방식으로 동작하게 할 가능성이 높다. 예를 들어, 게스트 계정으로 실행되는 프로세스가 이러한 방식으로 권한 있는 계정으로 실행되는 다른 프로세스를 손상시킬 수 있다. 이는 DLL에서 공유 섹션 사용을 피해야 하는 중요한 이유이다.

특정 실행 파일 압축기(예: UPX)에 의해 DLL이 압축되면 모든 코드 섹션이 읽기 및 쓰기로 표시되며 공유되지 않는다. 읽기-쓰기 코드 섹션은 개인 데이터 섹션과 마찬가지로 각 프로세스에 비공개이다. 따라서 공유 데이터 섹션을 가진 DLL은 여러 프로그램에서 동시에 사용될 경우 압축해서는 안 된다. 각 프로그램 인스턴스가 DLL의 자체 복사본을 가지고 있어야 하므로 메모리 소비가 증가하기 때문이다.

### 가져오기 라이브러리
정적 라이브러리와 마찬가지로, DLL의 가져오기 라이브러리는 `.lib` 파일 확장자로 표시된다. 예를 들어, 파일 생성 및 메모리 관리와 같은 윈도우 기본 함수의 주 동적 라이브러리인 kernel32.dll은 `kernel32.lib`를 통해 링크된다. 가져오기 라이브러리와 실제 정적 라이브러리를 구별하는 일반적인 방법은 크기이다. 가져오기 라이브러리는 실제 DLL을 참조하는 심볼만 포함하고 링크 시간에 처리되므로 훨씬 작다. 그러나 둘 다 유닉스 ar 형식 파일이다.

동적 라이브러리로의 링크는 일반적으로 실행 파일을 빌드하거나 링크하여 생성할 때 가져오기 라이브러리로 링크함으로써 처리된다. 생성된 실행 파일은 모든 DLL 함수 호출이 참조되는 가져오기 주소 테이블(IAT)을 포함한다(각 참조된 DLL 함수는 IAT에 자체 항목을 포함한다). 런타임에 IAT는 별도로 로드된 DLL의 함수를 직접 가리키는 적절한 주소로 채워진다.

시그윈/MSYS 및 MinGW에서 가져오기 라이브러리는 관례적으로 `.dll.a` 접미사를 사용하며, 윈도우 DLL 접미사와 유닉스 ar 접미사를 모두 결합한다. 파일 형식은 유사하지만 가져오기를 표시하는 데 사용되는 심볼이 다르다(`_head_foo_dll` vs `__IMPORT_DESCRIPTOR_foo`). GNU 바이너리 유틸리티 도구 체인이 가져오기 라이브러리를 생성하고 링크할 수 있지만, DLL에 직접 링크하는 것이 더 빠르다. MinGW의 실험 도구인 genlib은 MSVC 스타일 심볼로 가져오기 라이브러리를 생성하는 데 사용할 수 있다.

### 심볼 분석 및 바인딩
DLL이 내보내는 각 함수는 숫자 서열 번호와 선택적으로 이름으로 식별된다. 마찬가지로 함수는 서열 번호 또는 이름으로 DLL에서 가져올 수 있다. 서열 번호는 DLL 내보내기 주소 테이블에서 함수의 주소 포인터 위치를 나타낸다. 내부 함수는 서열 번호로만 내보내는 것이 일반적이다. 대부분의 윈도우 API 함수는 다른 윈도우 릴리스에서도 이름만 유지되며, 서열 번호는 변경될 수 있다. 따라서 서열 번호로 윈도우 API 함수를 안정적으로 가져올 수 없다.

서열 번호로 함수를 가져오는 것은 이름으로 가져오는 것보다 약간 더 나은 성능을 제공한다. DLL의 내보내기 테이블은 이름순으로 정렬되어 있으므로 이진 검색 알고리즘을 사용하여 함수를 찾을 수 있다. 찾아진 이름의 인덱스는 내보내기 서열 번호 테이블에서 서열 번호를 찾는 데 사용된다. 16비트 윈도우에서는 이름 테이블이 정렬되지 않아 이름 조회 오버헤드가 훨씬 더 눈에 띄었다.

또한 실행 파일을 특정 DLL 버전에 바인딩할 수 있다. 즉, 컴파일 시간에 가져온 함수의 주소를 해결하는 것이다. 바인딩된 가져오기의 경우 링커는 가져오기가 바인딩된 DLL의 타임스탬프와 체크섬을 저장한다. 런타임에 윈도우는 동일한 버전의 라이브러리가 사용 중인지 확인하고, 그렇다면 가져오기 처리를 건너뛴다. 그렇지 않거나 라이브러리가 바인딩된 것과 다르면 윈도우는 일반적인 방식으로 가져오기를 처리한다.

바인딩된 실행 파일은 컴파일된 환경과 동일한 환경에서 실행될 경우 다소 빠르게 로드되고, 다른 환경에서 실행될 경우 정확히 동일한 시간에 로드되므로 가져오기를 바인딩하는 데 단점이 없다. 예를 들어, 모든 표준 윈도우 응용 프로그램은 해당 윈도우 릴리스의 시스템 DLL에 바인딩된다. 응용 프로그램의 가져오기를 대상 환경에 바인딩할 좋은 기회는 응용 프로그램 설치 중이다. 이렇게 하면 다음 OS 업데이트까지 라이브러리가 "바인딩된" 상태로 유지된다. 그러나 실행 파일의 체크섬이 변경되므로 서명된 프로그램이나 파일 버전을 관리하는 데 체크섬(예: MD5 체크섬)을 사용하는 구성 관리 도구에 의해 관리되는 프로그램에서는 수행할 수 없다. 최근 윈도우 버전이 모든 로드된 라이브러리에 대해 고정된 주소를 갖는 방식에서 벗어나면서(보안상의 이유로) 실행 파일을 바인딩할 기회와 가치가 감소하고 있다.

### 명시적 런타임 링크

DLL 파일은 런타임에 명시적으로 로드될 수 있는데, 마이크로소프트에서는 이를 단순히 런타임 동적 링크라고 부른다. 이는 `LoadLibrary`(또는 `LoadLibraryEx`) API 함수를 사용하여 수행한다. `GetProcAddress` API 함수는 이름으로 내보낸 심볼을 찾는 데 사용되며, `FreeLibrary`는 DLL을 언로드하는 데 사용된다. 이러한 함수는 POSIX 표준 API의 `dlopen`, `dlsym`, `dlclose`와 유사하다.

명시적 런타임 링크 절차는 함수 포인터를 지원하는 모든 언어에서 동일하며, 언어 구성이 아닌 윈도우 API에 의존한다.

### 지연 로딩
일반적으로 DLL의 가져오기 라이브러리에 연결된 애플리케이션은 DLL을 찾을 수 없으면 시작되지 않는다. 윈도우는 애플리케이션이 필요할 수 있는 모든 DLL을 찾을 수 없는 한 애플리케이션을 실행하지 않기 때문이다. 그러나 애플리케이션은 동적 라이브러리의 지연 로딩을 허용하도록 가져오기 라이브러리에 연결될 수 있다.
이 경우 운영 체제는 애플리케이션 시작 시 DLL을 찾거나 로드하려고 시도하지 않는다. 대신, 링커에 의해 애플리케이션에 스텁이 포함되어 있어, 해당 함수 중 하나가 호출될 때 `LoadLibrary` 및 `GetProcAddress`를 통해 DLL을 찾고 로드하려고 시도한다. DLL을 찾거나 로드할 수 없거나 호출된 함수가 존재하지 않으면 애플리케이션은 예외를 생성하며, 이는 적절히 처리될 수 있다. 애플리케이션이 예외를 처리하지 않으면 운영 체제에 의해 잡히고 오류 메시지와 함께 프로그램이 종료된다.

지연 로딩 메커니즘은 DLL이 로드될 때 및 DLL 함수가 호출될 때 애플리케이션이 추가 처리 또는 오류 처리를 수행할 수 있도록 알림 훅을 제공한다.

## 컴파일러 및 언어 고려 사항

### 델파이
소스 파일에서 `program` 대신 `library` 키워드가 사용된다. 파일 끝에는 `exports` 절에 내보낼 함수가 나열된다.

델파이는 DLL에서 함수를 가져오기 위해 `LIB` 파일이 필요하지 않다. DLL에 링크하려면 함수 선언에서 `external` 키워드를 사용하여 DLL 이름을 지정하고, 이어서 심볼 이름(다른 경우)을 지정하는 `name` 또는 인덱스를 식별하는 `index`를 사용한다.

### 마이크로소프트 비주얼 베이직
비주얼 베이직 (VB)에서는 런타임 링크만 지원되지만, `LoadLibrary` 및 `GetProcAddress` API 함수를 사용하는 것 외에도 가져온 함수의 선언이 허용된다.

선언을 통해 DLL 함수를 가져올 때, VB는 `DLL` 파일을 찾을 수 없으면 런타임 오류를 생성한다. 개발자는 오류를 잡아 적절히 처리할 수 있다.

VB에서 DLL을 만들 때 IDE는 ActiveX DLL만 만들 수 있도록 허용하지만, 사용자가 각 내보낸 함수의 순서 위치와 이름을 정의하는 .DEF 파일을 포함하도록 링커에 명시적으로 지시할 수 있는 방법이 만들어졌다. 이를 통해 사용자는 Visual Basic (버전 6 이하)을 사용하여 "Declare" 문을 통해 참조할 수 있는 표준 윈도우 DLL을 만들 수 있다.

### C 및 C++
마이크로소프트 Visual C++ (MSVC)는 C++ 표준에 여러 확장을 제공하여 함수를 C++ 코드에서 직접 가져오거나 내보낼 수 있도록 한다. 이러한 확장 기능은 GCC의 윈도우 버전을 포함한 다른 윈도우 C 및 C++ 컴파일러에서 채택되었다. 이 확장 기능은 함수 선언 앞에 `__declspec` 속성을 사용한다. C 함수가 C++에서 액세스될 때 C++ 코드에서도 `extern "C"`로 선언되어야 컴파일러에 C 링크를 사용해야 한다고 알려야 한다.

`__declspec` 속성을 사용하여 가져오거나 내보낸 함수를 지정하는 것 외에도, 프로젝트에서 사용하는 `[[.def file|DEF]]` 파일의 IMPORT 또는 EXPORTS 섹션에 나열할 수 있다. `DEF` 파일은 컴파일러가 아닌 링커에 의해 처리되므로 C++에만 국한되지 않는다.

DLL 컴파일은 `DLL` 및 `LIB` 파일을 모두 생성한다. `LIB` 파일(가져오기 라이브러리)은 컴파일 시간에 DLL에 연결하는 데 사용되며 런타임 링크에는 필요하지 않다. DLL이 컴포넌트 오브젝트 모델(COM) 서버가 아닌 한, `DLL` 파일은 PATH 환경 변수에 나열된 디렉터리 중 하나, 기본 시스템 디렉터리 또는 DLL을 사용하는 프로그램과 동일한 디렉터리에 배치되어야 한다. COM 서버 DLL은 regsvr32.exe를 사용하여 등록되며, 이는 DLL의 위치와 전역 고유 ID(GUID)를 레지스트리에 배치한다. 그러면 프로그램은 레지스트리에서 GUID를 찾아 DLL의 위치를 찾거나 클래스 식별자와 인터페이스 식별자를 사용하여 COM 객체 인스턴스를 간접적으로 만들 수 있다.

## 프로그래밍 예시

### DLL 가져오기 사용
다음 예시는 컴파일 시간에 DLL에 링크하기 위해 언어별 바인딩을 사용하여 심볼을 가져오는 방법을 보여준다.

**델파이**


```delphi
{$APPTYPE CONSOLE}

program Example;

// import function that adds two numbers
function AddNumbers(a, b : Double): Double; StdCall; external 'Example.dll';

// main program
var
   R: Double;

begin
  R := AddNumbers(1, 2);
  Writeln('The result was: ', R);
end.
```


**C**

`Example.dll`이 생성되었다고 가정하고 정적 링크 전에 프로젝트에 'Example.lib' 파일을 포함해야 한다. 'Example.lib' 파일은 DLL 컴파일 시 컴파일러에 의해 자동으로 생성된다. 위 문장을 실행하지 않으면 링커가 `AddNumbers`의 정의를 찾을 위치를 알 수 없어 링크 오류가 발생한다. 'Example.dll' DLL 파일도 다음 코드에 의해 .exe 파일이 생성되는 위치에 복사해야 할 수 있다.

```c
#include <windows.h>
#include <stdio.h>

// Import function that adds two numbers
extern "C" __declspec(dllimport) double AddNumbers(double a, double b);

int main(int argc, char *argv[])
{
    double result = AddNumbers(1, 2);
    printf("The result was: %f\n", result);
    return 0;
}
```


### 명시적 런타임 링크 사용
다음 예시는 언어별 윈도우 API 바인딩을 사용하여 런타임 로딩 및 링크 기능을 사용하는 방법을 보여준다.

네 가지 샘플 모두 DLL 사전 로드 공격에 취약하다는 점에 유의해야 한다. example.dll이 저자가 의도하지 않은 위치로 확인될 수 있기 때문이다(애플리케이션 디렉터리가 시스템 라이브러리 위치보다 우선하지 않고, HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode 또는 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\CWDIllegalInDLLSearch가 없으면 현재 작업 디렉터리가 시스템 라이브러리 디렉터리보다 먼저 검색됨). 따라서 악성 라이브러리 버전에 취약하다. 마이크로소프트의 안전한 라이브러리 로딩에 대한 지침은 참조를 참조하라. 즉, 애플리케이션 디렉터리와 현재 작업 디렉터리를 DLL 검색 경로에서 제거하려면 의 를 사용하거나, 현재 작업 디렉터리를 DLL 검색 경로에서 제거하려면 의 를 사용해야 한다.

#### 마이크로소프트 비주얼 베이직

```vbnet
Option Explicit
Declare Function AddNumbers Lib "Example.dll" _
(ByVal a As Double, ByVal b As Double) As Double

Sub Main()
	Dim Result As Double
	Result = AddNumbers(1, 2)
	Debug.Print "The result was: " & Result
End Sub
```


#### 델파이

```delphi
program Example;
  {$APPTYPE CONSOLE}
  uses Windows;
  var
  AddNumbers:function (a, b: integer): Double; StdCall;
  LibHandle:HMODULE;
begin
  LibHandle := LoadLibrary('example.dll');
  if LibHandle <> 0 then
    AddNumbers := GetProcAddress(LibHandle, 'AddNumbers');
  if Assigned(AddNumbers) then
    Writeln( '1 + 2 = ', AddNumbers( 1, 2 ) );
  Readln;
end.
```


#### C

```c
#include <windows.h>
#include <stdio.h>

// DLL function signature
typedef double (*importFunction)(double, double);

int main(int argc, char **argv)
{
	importFunction addNumbers;
	double result;
	HINSTANCE hinstLib;

	// Load DLL file
	hinstLib = LoadLibrary(TEXT("Example.dll"));
	if (hinstLib == NULL) {
		printf("ERROR: unable to load DLL\n");
		return 1;
	}

	// Get function pointer
	addNumbers = (importFunction) GetProcAddress(hinstLib, "AddNumbers");
	if (addNumbers == NULL) {
		printf("ERROR: unable to find DLL function\n");
		FreeLibrary(hinstLib);
		return 1;
	}

	// Call function.
	result = addNumbers(1, 3);

	// Unload DLL file
	FreeLibrary(hinstLib);

	// Display result
	printf("The result was: %f\n", result);

	return 0;
}
```


#### 파이썬
[섬네일|파이썬 인터프리터는 [외부 함수 인터페이스(FFI)를 제공하는  모듈을 사용하여 공유 라이브러리의 함수를 호출할 수 있다.]]
파이썬 ctypes 바인딩은 POSIX 시스템에서 POSIX API를 사용한다.

```python
import ctypes

my_dll = ctypes.cdll.LoadLibrary("Example.dll")

# The following "restype" method specification is needed to make
# Python understand what type is returned by the function.
my_dll.AddNumbers.restype = ctypes.c_double

p = my_dll.AddNumbers(ctypes.c_double(1.0), ctypes.c_double(2.0))

print("The result was:", p)
```


## 컴포넌트 오브젝트 모델
컴포넌트 오브젝트 모델(COM)은 DLL 및 EXE 파일에 객체의 구현을 호스팅하기 위한 바이너리 표준을 정의한다. 이는 해당 파일을 찾고 버전을 지정하는 메커니즘과 언어 독립적이고 기계 판독 가능한 인터페이스 설명을 제공한다. DLL에 COM 객체를 호스팅하는 것은 더 가볍고 클라이언트 프로세스와 리소스를 공유할 수 있도록 한다. 이를 통해 COM 객체는 Visual Basic 및 ASP와 같은 간단한 GUI 프런트엔드에 강력한 백엔드를 구현할 수 있다. 또한 스크립팅 언어에서도 프로그래밍할 수 있다.

## DLL 하이재킹
DLL 하이재킹, DLL 스푸핑, DLL 프리로드 또는 바이너리 플랜팅으로 흔히 알려진 취약점으로 인해, 많은 프로그램은 이러한 프로그램이 연 데이터 파일과 동일한 폴더에 포함된 악성 DLL을 로드하고 실행한다. 이 취약점은 2000년에 게오르기 구닌스키에 의해 발견되었다.
2010년 8월 ACROS Security가 이를 재발견하고 수백 개의 프로그램이 취약한 것으로 밝혀지면서 전 세계적으로 주목을 받았다.
안전하지 않은 위치, 즉 다운로드 또는 임시 디렉터리와 같이 사용자가 쓰기 가능한 폴더에서 실행되는 프로그램은 거의 항상 이 취약점에 취약하다.

## 같이 보기
* 라이브러리 (컴퓨팅)
* 링커 (컴퓨팅)
* 로더 (컴퓨팅)
* 정적 라이브러리
* DLL 지옥

## 각주

## 외부 링크
* Dynamic-Link Libraries - MSDN
* What is a DLL? - 마이크로소프트 지원

분류:라이브러리
분류:파일 포맷