가져 오기 라이브러리는 어떻게 작동합니까? 세부?


88

나는 이것이 괴짜들에게 아주 기본적인 것처럼 보일 수 있다는 것을 알고 있습니다. 그러나 나는 그것을 명확하게하고 싶다.

Win32 DLL을 사용하려면 일반적으로 LoadLibrary () 및 GetProcAdderss ()와 같은 API를 호출합니다. 하지만 최근에는 DirectX9로 개발 중이며 d3d9.lib , d3dx9.lib 등의 파일 을 추가해야 합니다.

LIB는 정적 링크 용이고 DLL은 동적 링크 용이라고 충분히 들었습니다.

그래서 내 현재 이해는 LIB가 메서드의 구현을 포함하고 최종 EXE 파일의 일부로 링크 타임에 정적으로 링크된다는 것입니다. DLL은 런타임에 동적으로로드되며 최종 EXE 파일의 일부가 아닙니다.

그러나 때로는 DLL 파일 과 함께 제공 되는 일부 LIB 파일 있으므로 다음과 같습니다.

  • 이 LIB 파일은 무엇입니까?
  • 그들이 의미하는 바를 어떻게 성취합니까?
  • 이러한 LIB 파일의 내부를 검사 할 수있는 도구가 있습니까?

업데이트 1

wikipedia를 확인한 후 이러한 LIB 파일이 import library 라는 것을 기억합니다 . 하지만 주 응용 프로그램과 DLL이 동적으로로드되는 방식이 궁금합니다.

업데이트 2

RBerteig가 말했듯이 DLL로 태어난 LIB 파일에는 일부 스텁 코드가 있습니다. 따라서 호출 순서는 다음과 같아야합니다.

내 주 응용 프로그램-> LIB의 스텁-> 실제 대상 DLL

그렇다면 이러한 LIB에는 어떤 정보가 포함되어야합니까? 다음을 생각할 수 있습니다.

  • LIB 파일은 해당 DLL의 전체 경로를 포함해야합니다. 따라서 DLL은 런타임에 의해로드 될 수 있습니다.
  • 각 DLL 내보내기 방법의 진입 점에 대한 상대 주소 (또는 파일 오프셋?)는 스텁에 인코딩되어야합니다. 따라서 올바른 점프 / 메소드 호출을 할 수 있습니다.

내가 맞아? 뭔가 더 있나요?

BTW : 가져 오기 라이브러리를 검사 할 수있는 도구가 있습니까? 내가 볼 수 있다면 더 이상 의심이 없을 것입니다.


4
가져 오기 라이브러리를 검사 할 수있는 도구와 관련된 질문의 마지막 부분에 대해 아무도 언급하지 않은 것을 확인했습니다. 비주얼 C와 함께 ++, 거기에 그것을 할 최소한 두 가지 방법은 다음과 같습니다 lib /list xxx.liblink /dump /linkermember xxx.lib. 이 스택 오버플로 질문을 참조하십시오 .
Alan

또한 및 유틸리티에 dumpbin -headers xxx.lib비해 더 자세한 정보를 제공합니다 . liblink
m_katsifarakis

답변:


102

DLL 파일에 대한 링크 는 컴파일 링크 타임에 암시 적으로 또는 런타임에 명시 적으로 발생할 수 있습니다 . 어느 쪽이든 DLL은 프로세스 메모리 공간에로드되고 내 보낸 모든 진입 점을 응용 프로그램에서 사용할 수 있습니다.

런타임에 명시 적으로 사용하는 경우, 사용 LoadLibrary()하고 GetProcAddress()수동으로 당신이 호출 할 필요가 함수에 대한 포인터를 DLL을로드하고 얻을.

프로그램이 빌드 될 때 암시 적으로 링크 된 경우 프로그램에서 사용하는 각 DLL 내보내기에 대한 스텁은 가져 오기 라이브러리에서 프로그램에 링크되고 해당 스텁은 프로세스가 시작될 때 EXE 및 DLL로로드 될 때 업데이트됩니다. (예, 여기서 조금 이상 단순화했습니다 ...)

이러한 스텁은 어딘가에서 가져와야 하며 Microsoft 도구 체인에서 가져 오기 라이브러리 라는 특수한 형식의 .LIB 파일에서 가져옵니다 . 필요한 .LIB는 일반적으로 DLL과 동시에 빌드되며 DLL에서 내 보낸 각 함수에 대한 스텁을 포함합니다.

혼란스럽게도 동일한 라이브러리의 정적 버전도 .LIB 파일로 제공됩니다. DLL에 대한 가져 오기 라이브러리 인 LIB가 일반적으로 일치하는 정적 LIB보다 더 작다는 점 (종종 훨씬 더 작음)을 제외하고 구분하는 사소한 방법은 없습니다.

GCC 도구 모음을 사용하는 경우 우연히 DLL과 일치하는 가져 오기 라이브러리가 실제로 필요하지 않습니다. Windows로 포팅 된 Gnu 링커 버전은 DLL을 직접 이해하고 필요한 대부분의 스텁을 즉석에서 합성 할 수 있습니다.

최신 정보

모든 너트와 볼트가 실제로 어디에 있는지 그리고 실제로 무슨 일이 일어나고 있는지 알기에 저항 할 수 없다면 MSDN에는 항상 도움이 될 무언가가 있습니다. Matt Pietrek의 기사 An In-Depth Look into the Win32 Portable Executable File Format 은 EXE 파일의 형식과로드 및 실행 방법에 대한 매우 완벽한 개요입니다. 원래 MSDN Magazine ca에 게재 된 이후로 .NET 등을 포함하도록 업데이트되었습니다. 2002.

또한 프로그램에서 사용하는 DLL을 정확히 파악하는 방법을 아는 것도 도움이 될 수 있습니다. 이를위한 도구는 Dependency Walker (일명 dependent.exe)입니다. 이 버전은 Visual Studio에 포함되어 있지만 최신 버전은 작성자가 http://www.dependencywalker.com/ 에서 구할 수 있습니다 . 링크 타임에 지정된 모든 DLL (초기로드 및 지연로드)을 식별 할 수 있으며 프로그램을 실행하고 런타임에로드하는 추가 DLL을 감시 할 수도 있습니다.

업데이트 2

다시 읽기에 대해 명확히하고 MSDN과의 일관성을 위해 암시 적명시 적 링크 라는 용어를 사용하기 위해 이전 텍스트의 일부를 다시 작성했습니다 .

따라서 라이브러리 함수를 프로그램에서 사용할 수있는 세 가지 방법이 있습니다. 분명한 후속 질문은 "어떻게 어떤 방법을 선택합니까?"입니다.

정적 연결은 프로그램 자체의 대부분이 연결되는 방식입니다. 모든 개체 파일이 나열되고 링커에 의해 EXE 파일로 함께 수집됩니다. 그 과정에서 링커는 모듈이 서로의 함수를 호출 할 수 있도록 전역 심볼에 대한 참조를 수정하는 것과 같은 사소한 작업을 처리합니다. 라이브러리는 정적으로 링크 될 수도 있습니다. 라이브러리를 구성하는 개체 파일은 링커가 필요한 기호를 포함하는 모듈을 검색하는 .LIB 파일의 라이브러리 관리자에 의해 함께 수집됩니다. 정적 링크의 한 가지 효과는 프로그램에서 사용하는 라이브러리의 모듈 만 링크된다는 것입니다. 다른 모듈은 무시됩니다. 예를 들어, 기존 C 수학 라이브러리에는 많은 삼각 함수가 포함되어 있습니다. 그러나 당신이 그것에 대해 링크하고 사용한다면cos(), 당신의 코드의 사본을 결국하지 않습니다 sin()또는 tan()당신은 또한 그 기능을 호출하지 않는 한. 풍부한 기능 세트가있는 대형 라이브러리의 경우 모듈을 선택적으로 포함하는 것이 중요합니다. 임베디드 시스템과 같은 많은 플랫폼에서 라이브러리에서 사용할 수있는 총 코드 크기는 장치에 실행 파일을 저장하는 데 사용할 수있는 공간에 비해 클 수 있습니다. 선택적으로 포함하지 않으면 해당 플랫폼을위한 프로그램 구축 세부 사항을 관리하기가 더 어려울 것입니다.

그러나 실행중인 모든 프로그램에 동일한 라이브러리 의 사본이 있으면 일반적으로 많은 프로세스를 실행하는 시스템에 부담이됩니다. 올바른 종류의 가상 메모리 시스템을 사용하면 동일한 콘텐츠를 가진 메모리 페이지가 시스템에 한 번만 있으면 여러 프로세스에서 사용할 수 있습니다. 이렇게하면 코드가 포함 된 페이지가 가능한 한 많은 다른 실행중인 프로세스에서 일부 페이지와 동일 할 가능성이 높아집니다. 그러나 프로그램이 런타임 라이브러리에 정적으로 링크되면 각기 다른 위치에서 메모리 맵을 처리하는 각기 다른 조합의 기능을 갖게되며, 그 자체로 프로그램이 아닌 경우 공유 가능한 코드 페이지가 많지 않습니다. 프로세스 이상에서 실행됩니다. 따라서 DLL의 아이디어는 또 다른 주요 이점을 얻었습니다.

라이브러리 용 DLL에는 모든 클라이언트 프로그램에서 사용할 수있는 모든 기능이 포함되어 있습니다. 많은 프로그램이 해당 DLL을로드하면 모두 해당 코드 페이지를 공유 할 수 있습니다. 모두가 이깁니다. (글쎄, DLL을 새 버전으로 업데이트하기 전까지는이 이야기의 일부가 아닙니다. Google DLL Hell은 이야기의 측면에 있습니다.)

따라서 새 프로젝트를 계획 할 때 가장 먼저 선택해야하는 것은 동적 연결과 정적 연결 사이입니다. 정적 연결을 사용하면 설치할 파일이 줄어들고 사용하는 DLL을 제 3자가 업데이트하지 않아도됩니다. 그러나 프로그램은 더 크고 Windows 에코 시스템의 좋은 시민이 아닙니다. 동적 연결을 사용하면 설치할 파일이 더 많아지고 사용하는 DLL을 타사에서 업데이트하는 데 문제가있을 수 있지만 일반적으로 시스템의 다른 프로세스에 더 친숙합니다.

DLL의 큰 장점은 주 프로그램을 다시 컴파일하거나 다시 연결하지 않고도로드하고 사용할 수 있다는 것입니다. 이를 통해 타사 라이브러리 공급자 (예 : Microsoft 및 C 런타임)가 라이브러리의 버그를 수정하고 배포 할 수 있습니다. 최종 사용자가 업데이트 된 DLL을 설치하면 해당 DLL을 사용하는 모든 프로그램에서 해당 버그 수정의 이점을 즉시 얻습니다. (일을 깨뜨리지 않는 한. DLL Hell을 참조하십시오.)

다른 장점은 암시 적 로딩과 명시 적 로딩의 차이에서 비롯됩니다. 추가로 명시 적로드 작업을 수행하면 프로그램이 작성되고 게시 될 때 DLL이 존재하지 않았을 수 있습니다. 이를 통해 예를 들어 플러그인을 검색하고로드 할 수있는 확장 메커니즘을 사용할 수 있습니다.


3
내 게시물을 삭제하고 이것을 찬성하는 것은 당신이 나보다 일을 더 잘 설명하기 때문입니다.) 좋은 대답입니다.
ereOn

2
@RBerteig : 훌륭한 답변에 감사드립니다. 여기 ( msdn.microsoft.com/en-us/library/9yd93633.aspx ) 에 따르면 약간만 수정 하면 DLL에 대한 동적 연결에는 로드 시간 암시 적 연결런타임 명시 적 연결의 두 가지 유형이 있습니다. 없음 컴파일시에 연결하지 않습니다 . 이제 기존의 정적 연결 (전체 구현이 포함 된 * .lib 파일에 연결)과 DLL에 대한 로드 시간 동적 연결 (가져 오기 라이브러리를 통해 ) 의 차이점이 무엇인지 궁금합니다 .
smwikipedia

1
계속 : 정적 연결로드 시간 동적 연결의 장단점은 무엇 입니까? 이 두 가지 접근 방식은 프로세스가 시작될 때 필요한 모든 파일을 주소 공간에로드하는 것 같습니다. 왜 2 개가 필요한가요? 감사.
smwikipedia

1
"objdump"와 같은 도구를 사용하여 .lib 파일 내부를 들여다보고 그것이 가져 오기 라이브러리인지 실제 정적 라이브러리인지 알아낼 수 있습니다. Linux에서 Windows 대상으로 크로스 컴파일 할 때 .a 파일 (.lib 파일의 mingw 버전)에서 'ar'또는 'nm'를 실행할 수 있으며 가져 오기 라이브러리에는 일반 .o 파일 이름이 있고 코드는 없습니다. (단지 'jmp'명령어), 정적 라이브러리에는 많은 함수와 코드가 있습니다.
don bright

1
작은 수정 : 런타임에 암시 적으로 링크 할 수도 있습니다 . 지연로드 된 DLL에 대한 링커 지원에서는 이에 대해 자세히 설명합니다. 이는 DLL 검색 경로를 동적으로 변경하거나 가져 오기 확인 실패를 정상적으로 처리하려는 경우 유용합니다 (예 : 새 OS 기능을 지원하지만 여전히 이전 버전에서 실행).
IInspectable

5

이러한 .LIB 가져 오기 라이브러리 파일은 Linker->Input->Additional Dependencies가져 오기 라이브러리 .LIB 파일에서 제공하는 링크 타임에 추가 정보가 필요한 dll을 빌드 할 때 다음 프로젝트 속성에서 사용됩니다 . 링커 오류가 발생하지 않도록 아래 예제에서 lib 파일을 통해 dll의 A, B, C 및 D를 참조해야합니다. (링커가 이러한 파일을 찾으려면 배포 경로를 포함해야 할 수도 있습니다. Linker->General->Additional Library Directories그렇지 않으면 제공된 lib 파일을 찾을 수 없다는 빌드 오류가 발생합니다.)

링커-> 입력-> 추가 종속성

솔루션이 모든 동적 라이브러리를 빌드하는 경우 대신 Common Properties->Framework and References대화 상자 아래에 노출 된 참조 플래그에 의존하여이 명시적인 종속성 사양을 피할 수있었습니다 . 이러한 플래그는 * .lib 파일을 사용하여 사용자를 대신하여 자동으로 링크를 수행하는 것으로 나타납니다. 프레임 워크 및 참조

그러나 이것은 구성이나 플랫폼에 특정한 것이 아닌 공통 속성을 말합니다 . 애플리케이션에서와 같이 혼합 빌드 시나리오를 지원해야하는 경우 정적 빌드를 렌더링하는 빌드 구성과 동적 라이브러리로 배포 된 어셈블리 하위 집합의 제한된 빌드를 빌드하는 특수 구성이있었습니다. 다양한 경우에 true로 설정된 Use Library Dependency InputsLink Library Dependencies플래그를 사용하여 빌드 할 항목을 얻고 나중에 단순화하기 위해 실현했지만 정적 빌드에 내 코드를 도입 할 때 많은 링커 경고를 도입했고 정적 빌드의 경우 빌드가 엄청나게 느 렸습니다. 나는 이런 종류의 경고를 많이 소개했다.

warning LNK4006: "bool __cdecl XXX::YYY() already defined in CoreLibrary.lib(JSource.obj); second definition ignored  D.lib(JSource.obj)

그리고 Additional Dependencies동적 빌드에 대한 링커를 만족시키기 위해 수동 사양을 사용하여 작업 속도를 늦추는 공통 속성을 사용하지 않음으로써 정적 빌더를 행복하게 유지했습니다. 동적 하위 집합 빌드를 배포 할 때 이러한 lib 파일은 런타임이 아닌 링크 타임에만 사용되므로 dll 파일 만 배포합니다.


3

라이브러리에는 정적, 공유 및 동적으로로드 된 라이브러리의 세 가지 종류가 있습니다.

정적 라이브러리는 연결 단계에서 코드와 연결되므로 공유 라이브러리 파일에서 찾을 스텁 (기호) 만있는 공유 라이브러리와 달리 실제로 실행 파일에 있습니다. 주 함수가 호출됩니다.

동적으로로드 된 라이브러리는 작성한 코드에 의해 필요할 때로드된다는 점을 제외하면 공유 라이브러리와 매우 유사합니다.


@ zacsek 감사합니다. 그러나 공유 라이브러리에 대한 귀하의 진술에 대해 잘 모르겠습니다.
smwikipedia

@smwikipedia : Linux에는 그것들이 있고, 저는 그것들을 사용하고 있습니다. 그래서 그것들은 가장 확실히 존재합니다. 또한 읽기 : en.wikipedia.org/wiki/Library_(computing)
졸탄 Szőcs에게

3
미묘한 차이입니다. 공유 및 동적 라이브러리는 모두 DLL 파일입니다. 차이점은로드 될 때입니다. 공유 라이브러리는 EXE와 함께 OS에 의해로드됩니다. 동적 라이브러리는 코드 호출 LoadLibrary()및 관련 API에 의해로드됩니다 .
RBerteig

[1]에서 DLL이 Microsoft의 공유 라이브러리 개념 구현임을 읽었습니다. [1] : en.wikipedia.org/wiki/Dynamic-link_library#Import_libraries
smwikipedia

프로그래밍 관점에서 보면 공유 라이브러리가 동적으로로드되었는지 여부에 관계없이 큰 차이가 있다는 것은 미묘한 차이라는 점에 동의하지 않습니다.
졸탄 Szőcs

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.