문제

종종 '정적으로 연결된'및 '동적으로 연결된'이라는 용어를 듣습니다. 종종 작성된 코드와 관련하여 , C ++ 또는 씨#. 그들은 무엇입니까, 정확히 무엇에 대해 이야기하고 있으며, 무엇을 연결하고 있습니까?

도움이 되었습니까?

해결책

소스 코드 (쓰기)에서 실행 가능한 코드 (실행되는 것)로 얻는 데있어 두 단계가 있습니다 (대부분의 경우 해석 코드 할인)가 있습니다.

첫 번째는 소스 코드를 객체 모듈로 바꾸는 컴파일입니다.

두 번째는 링크가 객체 모듈을 결합하여 실행 파일을 형성하는 것입니다.

무엇보다도 소스 코드 (예 : 데이터베이스 액세스 용 라이브러리, 네트워크 통신 및 그래픽 사용자 인터페이스) 또는 다른 언어로의 컴파일 코드를 보지 않고 타사 라이브러리를 실행 파일에 포함시킬 수 있도록 차별화됩니다. C 및 어셈블리 코드와 예를 들어)와 함께 연결합니다.

때를 정적으로 파일을 실행 파일에 연결하면 해당 파일의 내용이 링크 시간에 포함됩니다. 다시 말해, 파일의 내용은 실행 가능한 실행 파일에 물리적으로 삽입됩니다.

링크 할 때 동적으로, 링크 된 파일에 대한 포인터 (예 : 파일의 파일 이름)가 실행 파일에 포함되며 해당 파일의 내용은 링크 시간에 포함되지 않습니다. 나중에 만 가능합니다 운영 이러한 동적으로 연결된 파일을 구입 한 실행 파일은 디스크의 것과는 달리 실행 파일의 메모리 사본에만 구입합니다.

기본적으로 연기 된 연결 방법입니다. 짝수가 있습니다 실제로 내부의 함수를 호출하려고 할 때까지 동적으로 연결된 파일을 가져 오지 않는 Deferred Method (일부 시스템의 후기 바인딩이라고 함).

정적으로 연결된 파일은 링크 시간에 실행 파일에 '고정'되므로 변경되지 않습니다. 실행 파일로 참조 된 동적으로 연결된 파일은 디스크에서 파일을 교체하면 변경 될 수 있습니다.

이를 통해 코드를 다시 링크하지 않고도 기능에 대한 업데이트가 가능합니다. 로더는 실행할 때마다 다시 링크됩니다.

이것은 좋고 나쁘다 - 한편으로는 더 쉬운 업데이트와 버그 수정을 허용하며, 다른 한편으로는 업데이트가 양립 할 수없는 경우 프로그램이 중단 될 수있다. 이것은 때때로 일부 사람들이 두려운 "DLL HELL"에 책임이있다. 동적으로 연결된 라이브러리를 호환되지 않는 라이브러리로 교체하면 응용 프로그램이 파손될 수 있다고 언급합니다 (이를 수행하는 개발자는 사냥을하고 심각하게 처벌 될 것으로 예상됩니다).


로서 예시, 사용자가 컴파일하는 경우를 살펴 보겠습니다. main.c 정적 및 동적 링크 파일.

Phase     Static                    Dynamic
--------  ----------------------    ------------------------
          +---------+               +---------+
          | main.c  |               | main.c  |
          +---------+               +---------+
Compile........|.........................|...................
          +---------+ +---------+   +---------+ +--------+
          | main.o  | | crtlib  |   | main.o  | | crtimp |
          +---------+ +---------+   +---------+ +--------+
Link...........|..........|..............|...........|.......
               |          |              +-----------+
               |          |              |
          +---------+     |         +---------+ +--------+
          |  main   |-----+         |  main   | | crtdll |
          +---------+               +---------+ +--------+
Load/Run.......|.........................|..........|........
          +---------+               +---------+     |
          | main in |               | main in |-----+
          | memory  |               | memory  |
          +---------+               +---------+

정적 케이스에서 기본 프로그램 및 C 런타임 라이브러리가 링크 시간 (개발자에 의해)에 링크되어 있음을 알 수 있습니다. 사용자는 일반적으로 실행 파일을 다시 링크 할 수 없으므로 라이브러리의 동작에 붙어 있습니다.

역동적 인 경우, 기본 프로그램은 C 런타임 가져 오기 라이브러리와 연결되어 있습니다 (동적 라이브러리의 내용을 선언하지만 실제로는 그렇지 않습니다. 정의하다 그것). 이를 통해 실제 코드가 없어도 링커가 링크 될 수 있습니다.

그런 다음 런타임에 운영 체제 로더는 기본 프로그램을 C 런타임 DLL (동적 링크 라이브러리 또는 공유 라이브러리 또는 기타 명명법)과 늦게 연결합니다.

C 런타임의 소유자는 언제든지 새 DLL을 떨어 뜨려 업데이트 또는 버그 수정을 제공 할 수 있습니다. 앞서 언급했듯이 이것은 장점과 단점이 있습니다.

다른 팁

이 질문에 대한 좋은 대답은 어떤 연결이 무엇인지 설명해야한다고 생각합니다. ~이다.

일부 C 코드 (예 : 일부)를 컴파일하면 기계 언어로 변환됩니다. 실행될 때 프로세서가 추가, 빼기, 비교, "goto", 메모리를 읽고 메모리를 쓰고, 그 종류의 일을하는 일련의 바이트 시퀀스. 이 물건은 객체 (.o) 파일에 저장됩니다.

이제 오래 전에 컴퓨터 과학자들은이 "서브 루틴"을 발명했습니다. 이 chink-of-code and receturn-here를 실행합니다. 그들이 가장 유용한 서브 루틴을 특별한 장소에 저장하고 필요한 프로그램에서 사용할 수 있다는 것을 깨달았습니다.

이제 초기에는 프로그래머 가이 서브 루틴이 위치한 메모리 주소를 펀칭해야합니다. 같은 것 CALL 0x5A62. 메모리 주소를 변경 해야하는 경우 이것은 지루하고 문제가되었습니다.

따라서 프로세스가 자동화되었습니다. 당신은 전화하는 프로그램을 작성합니다 printf(), 그리고 컴파일러는 메모리 주소를 모릅니다. printf. 따라서 컴파일러는 방금 씁니다 CALL 0x0000, "이 0x0000을 메모리 위치로 바꿔야한다는 객체 파일에 메모를 추가합니다. printf".

정적 링키지 LD) 추가 printf의 기계 코드는 실행 파일에 직접 직접, 0x0000을 주소로 변경합니다. printf. 이것은 실행 파일이 생성 될 때 발생합니다.

동적 연결은 위의 단계가 발생하지 않음을 의미합니다. 실행 파일 아직 "0x000을 printf의 메모리 위치로 바꿔야한다"라는 메모가 있습니다. 운영 체제의 로더는 Printf 코드를 찾고 메모리에로드 한 다음 호출 주소를 수정해야합니다. 프로그램이 실행될 때마다.

프로그램이 정적으로 연결될 일부 기능을 호출하는 것이 일반적입니다 (표준 라이브러리 기능 : printf 일반적으로 정적으로 연결되어 있습니다) 및 동적으로 연결된 기타 기능입니다. 정적은 실행 파일의 "일부"가되고 실행 파일이 실행될 때 동적 인 것 "에 합류".

두 방법 모두에는 장점과 단점이 있으며 운영 체제간에 차이가 있습니다. 그러나 당신이 묻지 않았기 때문에, 나는 이것을 여기서 끝내겠습니다.

정적으로 연결된 라이브러리는 컴파일 시간에 연결됩니다. 동적으로 연결된 라이브러리는 실행 시간에로드됩니다. 정적 링크는 라이브러리 비트를 실행 파일로 굽습니다. 동적 링크는 라이브러리를 참조하는 것만으로 구워집니다. 다이나믹 라이브러리의 비트는 다른 곳에 존재하며 나중에 교체 할 수 있습니다.

위의 게시물 중 어느 것도 없기 때문입니다 실제로 방법을 보여줍니다 정적으로 무언가를 연결하고 당신이 올바르게했는지 확인하려면이 문제를 해결할 것입니다.

간단한 C 프로그램

#include <stdio.h>

int main(void)
{
    printf("This is a string\n");
    return 0;
}

C 프로그램을 동적으로 연결합니다

gcc simpleprog.c -o simpleprog

그리고 달리기 file 이진에서 :

file simpleprog 

그리고 그것은 그것이 선을 따라 동적으로 연결되어 있음을 보여줄 것입니다.

"SimpleProg : ELF 64 비트 LSB 실행 파일, X86-64, 버전 1 (SYSV), 동적으로 연결 (공유 LIBS를 사용), GNU/Linux 2.6.26, buildId [SHA1] = 0xf71572611A8B04F6809D1C0D75C6028F0F, NOT STRUPE"

대신 이번에는 프로그램을 정적으로 연결하겠습니다.

gcc simpleprog.c -static -o simpleprog

이 정적으로 연결된 바이너리에서 실행 파일이 다음과 같습니다.

file simpleprog 

"SimpleProg : ELF 64 비트 LSB 실행 파일, X86-64, 버전 1 (GNU/Linux), GNU/Linux 2.6.26, buildid [SHA1] = 0x8c0B12550801C5A7C7434647B7DC65A644D612B, NOT STRIPPENT"

그리고 당신은 그것이 행복하게 정적으로 연결되어 있음을 알 수 있습니다. 그러나 슬프게도 모든 라이브러리가 이러한 방식으로 정적으로 링크하는 것이 간단하지는 않으며 libtool 또는 객체 코드와 C 라이브러리를 직접 연결합니다.

운 좋게도 많은 내장 된 C 라이브러리와 같은 musl 거의 모든 것에 대한 정적 링크 옵션을 제공합니다 전부는 아니라면 그들의 도서관의.

지금 strace 당신이 만든 이진은 프로그램이 시작되기 전에 액세스 할 수있는 라이브러리가 없음을 알 수 있습니다.

strace ./simpleprog

이제 출력과 비교하십시오 strace 동적으로 연결된 프로그램에서 정적으로 연결된 버전의 스트레이크가 훨씬 짧다는 것을 알 수 있습니다!

(C#을 모르지만 VM 언어에 대한 정적 연결 개념을 갖는 것은 흥미 롭습니다)

동적 링크에는 프로그램에서만 참조 할 수있는 필요한 기능을 찾는 방법을 아는 것이 포함됩니다. 언어 런타임 또는 OS는 파일 시스템, 네트워크 또는 컴파일 된 코드 캐시에서 코드 조각을 검색하고 참조와 일치 한 다음 몇 가지 측정을 수행하여 재배치와 같은 메모리의 프로그램 이미지에 통합합니다. 그들은 모두 런타임에 이루어집니다. 수동으로 또는 컴파일러에 의해 수행 할 수 있습니다. 엉망이 될 위험 (즉, DLL Hell)으로 업데이트 할 수있는 능력이 있습니다.

정적 링크는 컴파일 시간에 수행되며, 모든 기능 부품이있는 곳에 컴파일러를 알려주고 통합하도록 지시합니다. 검색, 모호성, 재 컴파일없이 업데이트 할 수있는 능력이 없습니다. 모든 종속성은 신체적으로 프로그램 이미지와 하나입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top