일부 공유 라이브러리가 마치 실행 파일인 것처럼 실행되는 이유와 방법은 무엇입니까?

일부 공유 라이브러리가 마치 실행 파일인 것처럼 실행되는 이유와 방법은 무엇입니까?

32비트 Linux 시스템에서는 다음을 호출하세요.

$ /lib/libc.so.6

64비트 시스템의 경우

$ /lib/x86_64-linux-gnu/libc.so.6

셸에서 다음 출력을 제공합니다.

GNU C Library stable release version 2.10.1, by Roland McGrath et al.
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.4.0 20090506 (Red Hat 4.4.0-4).
Compiled on a Linux >>2.6.18-128.4.1.el5<< system on 2009-08-19.
Available extensions:
    The C stubs add-on version 2.1.2.
    crypt add-on version 2.1 by Michael Glad and others
    GNU Libidn by Simon Josefsson
    Native POSIX Threads Library by Ulrich Drepper et al
    BIND-8.2.3-T5B
    RT using linux kernel aio
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.

이런 일이 발생하는 이유와 방법은 무엇이며, 다른 공유 라이브러리에서도 동일한 작업을 수행하려면 어떻게 해야 합니까?

/usr/lib실행 파일을 찾아보니 /usr/lib/libvlc.so.5.5.0실행 결과가 나왔습니다.세그멘테이션 오류. :-/

답변1

라이브러리에는 main()함수 또는 이에 상응하는 진입점이 있으며 실행 파일과 공유 개체로 모두 사용할 수 있는 방식으로 컴파일됩니다.

이것은추천나에게는 작동하지 않지만 이를 수행하는 방법에 대해.

이것은 또 다른 것입니다SO에 대한 유사한 질문에 대한 답변, 뻔뻔하게 표절하고, 수정하고, 설명을 추가하겠습니다.

먼저, 예제 라이브러리의 소스는 다음과 같습니다 test.c.

#include <stdio.h>                  

void sayHello (char *tag) {         
    printf("%s: Hello!\n", tag);    
}                                   

int main (int argc, char *argv[]) { 
    sayHello(argv[0]);              
    return 0;                       
}                   

컴파일:

gcc -fPIC -pie -o libtest.so test.c -Wl,-E

여기서 우리는 공유 라이브러리( -fPIC)를 컴파일하지만 링커에게 그것이 일반 실행 파일임을 알리고( ) 효율적으로 링크될 수 있도록 -pie심볼 테이블을 내보낼 수 있도록( ) 만듭니다 .-Wl,-E

그리고 file공유 객체라고 할지라도 실행 파일로 작동합니다.

> ./libtest.so 
./libtest.so: Hello!

이제 동적 연결이 실제로 가능한지 확인해야 합니다. 예제 프로그램 program.c:

#include <stdio.h>

extern void sayHello (char*);

int main (int argc, char *argv[]) {
    puts("Test program.");
    sayHello(argv[0]);
    return 0;
}

이를 사용하면 extern헤더를 생성할 필요가 없어집니다. 이제 컴파일하세요:

gcc program.c -L. -ltest

libtest.so실행하기 전에 동적 로더에 경로를 추가해야 합니다 .

export LD_LIBRARY_PATH=./

지금:

> ./a.out
Test program.
./a.out: Hello!

ldd a.out에 대한 링크가 표시 됩니다 libtest.so.

이것이 glibc가 실제로 컴파일되는 방식이라고 의심됩니다. glibc 자체만큼 이식성이 높지는 않지만( man gcc-fPIC스위치 참조 -pie) 기본 메커니즘을 보여주기 때문입니다. 실제 세부 사항을 알려면 소스 makefile을 살펴봐야 합니다.

답변2

GitHub의 임의 glibc 저장소에서 답변을 찾아보겠습니다. 이 버전은 파일에 "배너"를 제공합니다.version.c.

동일한 파일에는 몇 가지 흥미로운 점이 있습니다. __libc_print_version텍스트를 표준 출력으로 인쇄하는 기능과 __libc_main (void)진입점으로 문서화된 기호입니다. 따라서 라이브러리를 실행할 때 이 기호가 호출됩니다.

그렇다면 링커나 컴파일러는 이것이 진입점 함수라는 것을 어떻게 정확히 알 수 있을까요?

더 깊이 파헤쳐보자파일 생성. 링커 플래그 중에는 흥미로운 플래그가 있습니다.

# Give libc.so an entry point and make it directly runnable itself.
LDFLAGS-c.so += -e __libc_main

이는 라이브러리 진입점을 설정하는 데 사용되는 링커 플래그입니다. 라이브러리를 빌드할 때 -e function_name링커에 플래그를 제공하여 실행 가능한 동작을 활성화할 수 있습니다. 정확히 어떤 역할을 하나요? 우리에게 보여줘수동(다소 오래되었지만 여전히 유효함):

링커 명령 언어에는 출력 파일의 첫 번째 실행 가능 명령(해당 진입점)을 정의하기 위해 특별히 설계된 명령이 포함되어 있습니다. 인수는 상징적인 이름입니다.

입력(기호)

기호 할당과 마찬가지로 ENTRY 명령은 명령 파일에 독립 실행형 명령으로 배치하거나 SECTIONS 명령 내의 섹션 정의에 배치할 수 있습니다(레이아웃에 가장 적합한 위치).

ENTRY는 진입점을 선택하는 여러 방법 중 하나일 뿐입니다. 다음 방법 중 하나로 이를 표시할 수 있습니다(우선순위 내림차순으로 표시됨: 목록에서 더 높은 메소드가 더 낮은 메소드를 대체함).

the `-e' entry command-line option;
the ENTRY(symbol) command in a linker control script;
the value of the symbol start, if present;
the address of the first byte of the .text section, if present;
The address 0. 

예를 들어, 다음 규칙을 사용하여 할당문으로 진입점을 생성할 수 있습니다. 입력 파일에 시작 기호가 정의되어 있지 않으면 간단히 정의하여 적절한 값을 할당할 수 있습니다.

시작 = 0x2020;

이 예에서는 절대 주소를 보여 주지만 어떤 표현식이라도 사용할 수 있습니다. 예를 들어 입력 개체 파일이 진입점으로 다른 기호 이름 규칙을 사용하는 경우 시작하려는 시작 주소가 포함된 기호의 값을 할당할 수 있습니다.

시작 = 기타 기호;

(현재 문서를 찾을 수 있습니다여기)

ld-e명령줄 옵션 (가장 널리 사용되는 솔루션) 을 제공하거나 , 함수 기호를 제공 start하거나, 어셈블러에 대한 기호 주소를 지정하는 경우 링커는 실제로 진입점 함수가 있는 실행 파일을 만듭니다.

그러나 다른 링커와의 작동이 보장되지는 않는다는 점에 유의하십시오(llvm의 lld에 동일한 플래그가 있는지는 모르겠습니다). 왜 이것이 SO 파일에 대한 정보를 제공하는 것 이외의 목적을 가지고 있는지 모르겠습니다.

관련 정보