• Library
• 자주쓰이는 함수들을 중복 개발하는 것을 피하기 위해 표준화된 함수 및 데이
터 타입을 모듈화한 것
• Static Link Library
• 정적 링크, 컴파일 시점에 라이브러리가 링커에 의해 연결되어 실행 파일의 일
부분이 된다.
• DLL(Dynamic Link Library)
• 동적 링크, 실행 파일에서 해당 라이브러리를 사용 시에, 라이브러리 파일을 참
조해 기능을 호출한다.
• 컴파일 시점에 실행 파일에 함수를 복사하지 않고, 함수의 위치정보만 갖고 그
함수를 호출한다.
• 프로그램 런타임 중 원하는 때에 링크한다.
Static Library Vs. Dynamic Link Library
4.
• Static Library
•가상 메모리에 전부 올린다.
• DLL(Dynamic Link Library)
• 가상 메모리에 필요할 때 매핑한다
Static Library Vs. Dynamic Link Library
5.
• Static Library
•다른 실행 파일이 같은 정적 라이브러리 영역을 필요로 해도, 다 반환하고 정적 라이브러리 영역을 다시 로드
• DLL(Dynamic Link Library)
• 메모리 상에서 다른 실행 파일과 공유 가능. 메모리 공간 및 로드 시간 절약.
Static Library Vs. Dynamic Link Library
6.
• KerneI32.dll
• 메모리관리, 프로세스 관리, 스레드 관리와 관련된 함수들을 포함
• User32.dll
• 윈도우 생성, 메시지 송신과 같은 사용자 인터페이스와 관련된 함수를 포함
• GDI32.dll
• 그래픽 이미지를 그리거나 텍스트를 출력하는 등의 작업을 수행하는 함수를 포함
윈도우 주요 DLL
7.
• 애플리케이션의 기능확장
• DLL은 주소 공간에 동적으로 로드 가능. 즉, 애플리케이션이 수행 중이라도 추가 작업을 위한 코드를 로드할 수 있다. 제품의
기능을 확장하거나 보강하려는 경우 유용
• 프로젝트 관리의 단순화
• 여러 그룹이 각기 개발 작업을 수행하는 경우, DLL을 사용으로 프로젝트 관리를 좀 더 쉽게 할 수 있다.
• 메모리 절약
• 두 개 이상의 애플리케이션이 동일한 DLL을 램에 단 한 번만 로드하고, 로드한 내용을 공유할 수 있다.
• 예) C/C++ 런타임 라이브러리
• 플랫폼 차별성 해소
• 윈도우 버전별로 서로 다른 함수들을 제공. 이러한 함수를 사용하는 기능을 DLL 파일로 분리해 두면 여러 버전의 윈도우에서
도 정상적으로 프로세스가 기동될 수 있다
DLL을 사용해야 하는 이유
8.
• DLL은 단순히다른 애플리케이션이나 DLL에서 호출하는 함수들의 집합인 모듈을 구현하는 소스 코드로 구성
• DLL 소스 코드 컴파일 후 링크 작업 수행시, 링커에 반드시 /DLL 스위치 지정
• 링커는 DLL 파일 이미지에 특수 정보를 포함. 이를 통해 운영체제 로더는 해당 파일 이미지가 DLL 파일임을 인지
/DLL 스위치
9.
• DLL 파일은애플리케이션이 DLL 내 함수를 호출하기 전에 반드시 주소 공간에 매핑되어 있어야 한다.
• 묵시적인 로드타임 링킹(Implicit load-time linking)
• 명시적인 런타임 링킹(explicit run-time linking)
• DLL이 로드가 완료되고 나면 DLL 고유의 특성은 거의 없어진다.
• 스레드는 DLL의 내용을 단순히 프로세스의 주소 공간에 로드된 추가적인 코드와 데이터들로 인식
• DLL 함수 호출
• 스레드가 DLL의 함수를 호출하면, DLL 함수는 스레드의 스택에서 전달된 인자값을 가져오고, 지역변수를 할당
• DLL 함수 내부에서 생성하는 모든 오브젝트도 함수를 호출하는 스레드나 프로세스가 소유
• 예) DLL 내 함수가 VirtualAlloc 함수 호출시 해당 함수를 호출한 스레드의 프로세스의 주소 공간에 영역 예약
• DLL 파일 내 전역으로 선언된 정적변수는 실행 파일의 경우와 동일하게 새로운 인스턴스 생성
• 카피 온 라이트 메커니즘
01. DLL과 프로세스 주소 공간
10.
02. 전반적인 모습– DLL 생성
4) 링커는 .obj 모듈을 결합하여 DLL 생성
1) 익스포트할 원형/구조체/심벌 등을 정의하고 있는 헤더
2) 익스포트할 함수/변수를 구현하고 있는 C/C++ 소스 파일
3) 컴파일러는 C/C++ 소스 파일 각각에 대해 .obj 파일 생성
5) 링커는 하나 이상의 함수/변수가 익스포트된 경우
.Iib 파일 생성
• 그림은 단순화를 위해 DLL은 실행 모듈이 사용하는 함수와 변수를
익스포트하는 모듈로 제한.
• DLL 모듈도 다른 DLL 모듈의 함수 등을 임포트한다
11.
02. 전반적인 모습– EXE 생성 및 실행
6) 임포트할 원형/구조체/ 심벌 등을 정의하고 있는 헤더
7) 임포트할 함수/변수를 참조하는 C/C++ 소스파일
8) 컴파일러는 C/C++ 소스 파일 각각에 대해 obj 파일 생성
9) 링커는 임포트한 함수/변수들의 위치를 .Iib 파일을 이용하여
확인하고 .obj 모률을 결합하여 .exe 파일 생성
(실행 파일은 어떤 DLL이 필요하며 임포트한 심벌이 무엇인지에
대한 임포트 테이블 리스트를 가지고 있다.)
10) 로더는 exe를 위한 주소 공간 생성
11) 로더는 주소 공간에 필요한 DLL 로드.
프로세스의 주 스레드 수행.
애플리케이션 실행 .
12.
1. 헤더 파일작성
• DLL이 익스포트하는 함수의 원형, 구조체 심벌을 포함하는 헤더 파일을 작성
• DLL 파일의 모든 소스 코드들은 이 헤더 파일을 인클루드
• DLL 모듈을 사용하는 실행 모듈에도 동일한 헤더 파일을 사용
2. DLL 소스 코드 모듈 작성
1. DLL 모듈의 함수와 변수를 구현하는 C/C++ 소스 코드 모듈 작성
2. 이러한 소스 코드 모듈은 실행 모듈을 생성할 때에는 사용되지 않는다. (소스 코드를 공개하지 않아도 된다.)
3. DLL 이미지 파일 생성
1. 컴파일러는 각 소스 모듈을 컴파일하여 .obj 모듈을 생성 (소스 코드 모률별로 .obj 모률이 하나씩 생성)
2. 링커는 .obj 모듈의 내용을 결합하여 단일의 DLL 이미지 파일을 생성
4. .lib 파일 생성
• 링커는 DLL의 소스 코드가 하나 이상의 함수 혹은 변수를 익스포트한다면 .lib 파일을 생성
• .lib 파일은 단순히 DLL 파일이 익스포트하고 있는 함수나 변수의 심벌 이름만을 유지
• 이 파일은 실행 모듈을 생성할 때 반드시 필요
DLL 생성
13.
1. 실행 파일소스 코드 모듈 작성
• DLL 파일의 함수, 변수, 데이터 구조, 심벌 등을 참조하고자 하는 소스 코드 모듈은 DLL의 헤더 파일을 인클루드
• 실행 모듈 내부 C/C++ 소스 코드는 DLL 의 헤더 파일에서 정의하고 있는 함수나 변수들을 사용할 수 있다.
2. 실행 파일 이미지 생성
• 컴파일러는 소스 코드 모듈을 컴파일하여 .obj 모듈을 생성 (소스 코드 모듈별로 하나씩 .obj 생성)
• 링커는 .obj 모듈의 내용을 결합하여 단일의 실행 파일 이미지를 생성
• 실행 모듈은 파일 수행에 필요한 DLL 모듈의 이름을 포함하고 있는 임포트 섹션을 가지고 있다.
3. 실행 모듈 수행
• 로더는 새로운 프로세스를 위한 가상 주소 공간을 생성하고 실행 모듈을 매핑
• 로더는 실행 모듈의 임포트 섹션을 분석하고 필요한 DLL을 시스템으로부터 찾아 프로세스의 주소 공간에 매핑
• 실행 모듈과 모든 DLL 모듈이 프로세스의 주소 공간 내에 매핑되면 주 스레드가 실행되고, 애플리케이션이 실행
실행 모듈 생성
14.
• DLL은 변수,함수, C++ 클래스를 다른 모듈에 익스포트할 수 있다.
• 코드의 계층적 추상화 유지 및 코드 유지 관리를 위해 변수를 익스포트하는 것은 좋지 않다.
• 익스포트한 C++ 클래스는 동일 회사의 컴파일러로 컴파일해야만 사용할 수 있다.
• 유지 보수를 위해 DLL 별로 헤더 파일을 하나씩만 구성하는 것이 좋다.
DLL 모듈
15.
실행 파일과 DLL소스 코드 양쪽에서 시용할 수 있는 헤더
실행 파일의 소스 코드에서는 헤더 파일을 인클루드하기 전에
MYLIBAPI를 정의하지 않는다.
헤더 파일은 MYLIBAPI가 정의되어 있지 않으면 MYLIBAPI를
declspec(dllimport)로 정의.
declspec(dllimport)가 정의되면 컴파일러는 실행 파일의 소스 코
드가 DLL 모듈 내에 포함된 변수와 함수들을 임포트하는 것으로
판단
16.
실행 파일과 DLL소스 코드 양쪽에서 시용할 수 있는 헤더
헤더 파일의 익스포트하고자 하는 모든 변수와 함수 앞쪽에
MYLIBAPI 구분자를 사용하고 있다
17.
DLL 소스 코드
소스코드에서 DLL 헤더 인클루드 전 __declspec(dllexport) 정의
컴파일러는 모든 변수, 함수, 클래스 앞에 __declspec(dllexport)가
있는 것으로 보고 DLL 모듈로부터 익스포트되는 것이라 판단.
• MYLIBAPI 심벌의 extern “C” 한정자는 C++ 코드에만 사용
• 보통 C++ 컴파일러는 함수와 변수의 이름을 변경해서 링크 문
제 유발
• 예를 들어 DLL은 C++로 작성하고 실행 파일은 C로 작성하면,
DLL 파일 생성할 때는 함수의 이름이 변경되지만, 실행 파일에
서는 참조 함수의 이름이 변경되지 않기 때문에, 링크하는 과
정에서 존재하지 않는 심벌 참조 에러 발생
• extern "C" 를 사용하면 컴파일러는 변수와 함수의 이름을 변경
하지 않고, C나 다른 언어에서도 DLL의 변수나 함수를 사용할
수 있다.
18.
익스포트 의미 (_declspec(dllexport)한정자)
• 마이크로소프트의 C/C++ 컴파일러가 이러한 한정자를 발견하면 .obj 파일에 추가 정보를 기록
• 링커는 링크 작업 중 .obj 파일에서 익스포트할 변수, 함수, 클래스에 대한 정보들을 확인하고, .lib 파일을 생성
• .lib 파일은 DLL 이 익스포트하는 심벌의 목록을 가진다.
• 링커는 DLL 파일의 익스포트 섹션에 익스포트하는 심벌에 한 정보를 테이블 형태로 포함
• 링커는 DLL 모듈내 각 심벌의 위치를 나타내는 상대 가상 주소(relative virtual address) 값(=오프셋 값)도 DLL에 포함
19.
Kernel32.dll 의 익스포트섹션
• Visual Studio 의 DumpBin.exe를 ( -exports 스위치와 함께) 사용하면 DLL의 익스포트 섹션을 살펴볼 수 있다.
20.
실행 모듈 생성
•실행 파일의 소스 코드에 DLL의 헤더 파일을 인클루드
• 실행 파일의 소스에는 MYLIBAPI 정의가 없기 때문에 MyLib.h 헤더 파
일 내에서 MYLIBAPI을 __declspec(dllimport) 정의
• 컴파일러는 __declspec(dllimport) 한정자로 해당 심벌이 DLL 모듈에
서 임포트된 것임을 확인
• 링커는 실행 모듈을 생성하기 위해 모든 .obj 모듈을 결합
• 링커는 .lib 파일을 통해 소스 코드의 심벌들이 어떤 DLL로부터 익스
포트되었는지 확인
• .lib 파일은 DLL 모듈이 익스포트하는 심벌들에 대한 목록
• 링커가 모든 심벌들의 위치를 확인하면 실행 파일이 탄생하게 된다.
21.
임포트 의미 (_declspec(dllimport)한정자)
• 사실 심벌을 임포트할 때 _declspec(dllimport)를 사용하지 않아도 되고, 단순히 표준의 extern 키워드만 사용해도 된다
• 하지만 참조하는 심벌이 DLL의 .lib 파일로부터 임포트될 것임을 미리 안다면 좀 더 효율적인 코드가 될 수 있다.
• 마이크로소프트 또한 모든 표준 윈도우 함수에 대해 이러한 방식을 사용하고 있다.
• 링커는 임포트된 심벌을 찾는 과정에서 임포트 섹션이라고 불리는 특수한 섹션을 실행 파일 내에 추가
• 임포트 섹션은 실행 파일이 필요로 하는 DLL 모듈과 해당 DLL 모듈에서 참조되는 심벌에 대한 목록이 포함
22.
Calc.exe 의 임포트섹션
• Visual Studio 의 DumpBin.exe를 ( -imports 스위치와 함께) 사용하면 DLL의 임포트 섹션을 살펴볼 수 있다.
23.
실행 모듈의 수행
•실행 파일이 수행되면 운영체제의 로더는 프로세스를 위한 가상 주소 공간을 생성
• 이후 로더는 실행 모듈을 프로세스의 주소 공간에 매핑
• 로더는 실행 파일의 임포트 섹션을 확인하여 필요한 DLL 파일들을 찾아서 프로세스의 주소 공간에 매핑
• 임포트 섹션 내 DLL 목록은 전체 경로는 미포함, 로더는 아래 순서로 사용자의 디스크 드라이브로부터 DLL을 검색
1. 실행 파일 이미지가 있는 디렉터리
2. GetSystemDirectory 함수의 반환값인 윈도우 시스템 디렉터리
3. 16 비트 시스템 디렉터리(윈도우 디렉터리 이하의 System 하위 폴더)
4. GetWindowsDirectory 함수의 반환 값인 윈도우 디렉터리
5. 프로세스의 현재 디렉터리
6. PATH 환경변수에 포함된 디렉터리
24.
실행 모듈의 수행
•DLL 모듈 찾아 매핑 후, 로더는 각 DLL 파일의 임포트 섹션을 조사해 추가적 으로 필요한 DLL 파일들을 매핑
• 만일 로더가 필요한 DLL 모률을 찾지 못하면 시용자에게 다음과 같은 메시지 박스를 나타낸다
• 이후 로더는 각각의 심벌 관련 DLL의 익스포트 섹션을 검토하고 심벌이 실제로 존재하는지를 확인
• 심벌이 존재하지 않으면 로더는 다음과 유사한 메시지 박스를 나타낸다
• 심벌이 존재하면 심벌의 RVA 정보를 가져와서 DLL 모듈이 로드되어 있는 가상 주소 공간에 값을 더한다.
• 이후 실행 모듈의 임포트 섹션 내에 계산된 가상 주소 값을 기록
• 코드에서 임포트된 심벌을 참조하면 임포트 섹션의 위치 정보로 임포트된 변수 함수 또는 C++ 클래스에 접근할 수 있다.
25.
실행 모듈의 수행
•로더가 모든 DLL을 로드하고 임포트 심벌의 정확한 주소 값을 임포트 섹션에 기록하려면 상당한 시간이 소요
• 애플리케이션 로딩 속도 향상을 위해 실행 파일과 DLL 모듈에 대해 시작 위치 변경과 바인딩 작업을 수행하는 것이 좋다.