'정적으로 링크 된'및 '동적으로 링크 된'은 무엇을 의미합니까?


229

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

답변:


445

소스 코드 (작성한 것)에서 실행 가능한 코드 (실행하는 것)로가는 데는 2 단계 (대부분의 경우 해석 된 코드 할인)가 있습니다.

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

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

그 중에서도 소스 코드 (데이터베이스 액세스, 네트워크 통신 및 그래픽 사용자 인터페이스 용 라이브러리 등)를 보거나 다른 언어로 코드를 컴파일하지 않고도 타사 라이브러리를 실행 파일에 포함시킬 수 있습니다. 예를 들어 C 및 어셈블리 코드)를 모두 연결합니다.

당신이 때 정적 실행 파일로 파일을 링크 해당 파일의 내용은 링크시에 포함되어 있습니다. 즉, 파일의 내용은 실행할 실행 파일에 실제로 삽입됩니다.

동적으로 링크하면 링크 되는 파일에 대한 포인터 (예 : 파일의 파일 이름)가 실행 파일에 포함되고 해당 파일의 내용은 링크 타임에 포함되지 않습니다. 나중에 경우에만의 실행 이 동적으로 링크 된 파일에서 구입하고 그들 만 디스크에 실행 파일이 아닌 하나의 메모리 복사본으로 구입하고있는 실행 파일을.

기본적으로 지연된 연결 방법입니다. 더있다 당신이 실제로 그 안에 함수를 호출 할 때까지 동적으로 링크 된 파일에 가져 오지 않습니다 (말 일부 시스템에 바인딩이라고도 함) 연기 방법.

정적으로 링크 된 파일은 링크 타임에 실행 파일에 '고정'되므로 변경되지 않습니다. 실행 파일이 참조하는 동적으로 링크 된 파일은 디스크의 파일을 바꾸는 것만으로 변경 될 수 있습니다.

이를 통해 코드를 다시 연결하지 않고도 기능을 업데이트 할 수 있습니다. 로더는 실행할 때마다 다시 연결됩니다.

이것은 좋고 나쁘다-한편으로는, 더 쉬운 업데이트와 버그 수정을 허용하고, 다른 한편으로는 업데이트가 호환되지 않으면 프로그램이 작동을 멈출 수 있습니다. 동적으로 연결된 라이브러리를 호환되지 않는 라이브러리로 바꾸면 응용 프로그램이 손상 될 수 있습니다 (이를 수행하는 개발자는 심각하게 사냥하고 처벌해야합니다).


예를 들어 , 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을 삭제하여 업데이트 또는 버그 수정을 제공 할 수 있습니다. 앞서 언급했듯이, 이것은 장단점이 있습니다.


11
내가 틀렸다면 정정하십시오. 그러나 Windows에서는 소프트웨어가 동적으로 연결되어 있어도 설치에 자체 라이브러리가 포함되는 경향이 있습니다. 패키지 관리자가있는 많은 Linux 시스템에서 동적으로 연결된 많은 라이브러리 ( "공유 객체")는 실제로 소프트웨어간에 공유됩니다.
Paul Fisher

6
@PaulF : Windows 공통 컨트롤, DirectX, .NET 등과 같은 것들이 응용 프로그램과 함께 많이 제공되는 반면 Linux에서는 apt 또는 yum 또는 이와 유사한 것을 사용하여 종속성을 관리하는 경향이 있으므로 그 의미가 맞습니다. . DLL이 공유하지 않는 경향이있는 자체 코드를 제공 하는 Win Apps .
paxdiablo

31
DLL을 업데이트하고 이전 버전과의 호환성을 깨뜨리는 사람들을 위해 9 번째 지옥에 특별한 장소가 있습니다. 예, 인터페이스가 사라지거나 수정되면 동적 링크가 힙에 속합니다. 그것이 완료되어서는 안되는 이유입니다. 꼭 function2 ()를 DLL에 추가하지만 사람들이 그것을 사용하는 경우 function ()을 변경하지 마십시오. 그것을 처리하는 가장 좋은 방법은 function2 ()를 호출하는 방식으로 function ()을 코딩하는 것이지만 function () 의 서명은 변경 하지 마십시오 .
paxdiablo

1
@Paul Fisher, 나는 이것이 늦었다는 것을 알고 있지만 ... Windows DLL과 함께 제공되는 라이브러리는 전체 라이브러리가 아니며 링커에 DLL이 무엇인지 알려주는 스텁입니다. 그런 다음 링커는 DLL을로드하기 위해 정보를 .exe에 자동으로 넣을 수 있으며 기호는 정의되지 않은 것으로 표시되지 않습니다.
Mark Ransom

1
@Santropedro, lib, import 및 DLL 이름의 의미에 따라 모든 것이 정확합니다. 접미사는 관습 일 뿐이므로 너무 많이 읽지 마십시오 (예 : DLL에 확장자 .dll또는 .so확장명 이있을 수 있음 ) . 정확한 설명이 아니라 개념 을 설명하는 것으로 답을 생각하십시오 . 그리고 텍스트에 따라, 이것은 단지 C 런타임 파일에 대한 정적 및 동적 링크를 보여주는 예제이므로 그렇습니다.`crt가 모든 파일에서 나타냅니다.
paxdiablo

221

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

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

오래 전, 컴퓨터 과학자들은이 "서브 루틴"을 발명했습니다. 이 코드 청크를 실행하십시오. 그들이 가장 유용한 서브 루틴이 특별한 장소에 저장 될 수 있고 그것들을 필요로하는 모든 프로그램에 의해 사용될 수 있다는 것을 깨닫기까지 너무 오래 걸리지 않았습니다.

이제 초창기 프로그래머는이 서브 루틴이 있던 메모리 주소를 입력해야했습니다. 같은 것 CALL 0x5A62. 메모리 주소를 변경해야하는 경우에는 지루하고 문제가있었습니다.

따라서 프로세스가 자동화되었습니다. 을 호출하는 프로그램을 작성 printf()하면 컴파일러는의 메모리 주소를 모릅니다 printf. 따라서 컴파일러는 단지을 쓰고 CALL 0x0000객체 파일에 "이 0x0000을 printf 의 메모리 위치로 바꿔야합니다"라는 메모를 추가합니다 .

정적 연결은 링커 프로그램 (GNU 파일은 ld 라고 함 )이 printf실행 파일에 직접 기계 코드를 추가 하고 0x0000을 주소로 변경 함을 의미합니다 printf. 실행 파일을 만들 때 발생합니다.

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

프로그램이 정적으로 링크되는 함수 ( printf일반적으로 정적으로 링크 된 것과 같은 표준 라이브러리 함수 )와 동적으로 링크 된 다른 함수를 호출하는 것이 일반적입니다. 정적 파일은 실행 파일의 "일부"가되고 동적 파일은 실행 파일이 실행될 때 "가입"합니다.

두 가지 방법 모두 장단점이 있으며 운영 체제마다 차이가 있습니다. 그러나 당신이 묻지 않았으므로 여기서 끝내겠습니다.


4
나도 그랬지만 답은 1 개만 선택할 수 있습니다.
UnkwnTech

1
Artelius, 나는이 미친 저수준 일들이 어떻게 작동하는지에 대한 당신의 설명에 대해 깊이 찾고 있습니다. 위의 것들에 대한 심도있는 지식을 얻기 위해 어떤 책을 읽어야하는지 답하십시오. 감사합니다.
mahesh

1
죄송합니다. 책을 추천 할 수 없습니다. 먼저 어셈블리 언어를 배워야합니다. 그런 다음 Wikipedia는 그러한 주제에 대한 적절한 개요를 제공 할 수 있습니다. GNU ld문서 를보고 싶을 수도 있습니다 .
Artelius 2009

31

정적으로 링크 된 라이브러리는 컴파일 타임에 링크됩니다. 동적으로 링크 된 라이브러리는 런타임에로드됩니다. 정적 링크는 라이브러리 비트를 실행 파일로 굽습니다. 동적 링크는 라이브러리를 참조 할 때만 굽습니다. 동적 라이브러리의 비트는 다른 곳에 존재하며 나중에 교체 될 수 있습니다.


16

위의 게시물 중 어느 것도 실제로 정적으로 링크 하는 방법보여 주지 않고 올바르게 수행했는지 확인 하므로이 문제를 해결할 것입니다.

간단한 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 : GNU / Linux 2.6.26, ELID 64 비트 LSB 실행 파일, x86-64, 버전 1 (SYSV), 동적 링크 (공유 라이브러리 사용), GNU / Linux 2.6.26, BuildID [sha1] = 0xf715572611a8b04f686809d90d1c0d75c6028f0f, 스트립되지 않음"

대신 이번에 프로그램을 정적으로 링크하자 :

gcc simpleprog.c -static -o simpleprog

이 정적으로 링크 된 바이너리에서 파일을 실행하면 다음이 표시됩니다.

file simpleprog 

"simpleprog : GNU / Linux 2.6.26 용 ELF 64 비트 LSB 실행 파일, x86-64, 버전 1 (GNU / Linux), 정적으로 링크 됨, BuildID [sha1] = 0x8c0b12250801c5a7c7434647b7dc65a644d6132b, 제거되지 않음"

그리고 당신은 그것이 정적으로 연결되어있는 것을 볼 수 있습니다. 그러나 안타깝게도 모든 라이브러리가 이러한 방식으로 정적으로 연결하는 것이 간단하지는 않으며 libtool, 수작업으로 객체 코드와 C 라이브러리를 사용 하거나 연결하는 데 많은 노력이 필요할 수 있습니다 .

같은 다행히 많은 임베디드 C 라이브러리 musl제공 정적 거의 모든 옵션을 연결하는 모든 경우에 자신의 라이브러리.

이제 strace작성한 바이너리는 프로그램을 시작하기 전에 액세스 한 라이브러리가 없음을 알 수 있습니다.

strace ./simpleprog

이제 strace동적으로 링크 된 프로그램 의 출력과 비교 하면 정적으로 링크 된 버전의 strace가 훨씬 짧습니다.


2

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

동적 연결에는 프로그램에서 참조 할 수있는 필수 기능을 찾는 방법을 알아야합니다. 언어 런타임 또는 OS는 파일 시스템, 네트워크 또는 컴파일 된 코드 캐시에서 참조와 일치하는 코드를 검색 한 다음 재배치와 같이 메모리의 프로그램 이미지에 통합하기 위해 몇 가지 조치를 취합니다. 그들은 모두 런타임에 완료됩니다. 수동으로 또는 컴파일러로 수행 할 수 있습니다. 엉망의 위험이있는 업데이트 기능 (즉, DLL 지옥)이 있습니다.

정적 링크는 컴파일 타임에 수행되며, 컴파일러는 모든 기능 부분이 어디에 있는지 알려주고 통합하도록 지시합니다. 재 컴파일 없이는 검색, 모호함, 업데이트 기능이 없습니다. 모든 종속성은 실제로 프로그램 이미지와 하나입니다.

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