일부 공유 라이브러리는 실행 가능한 것처럼 왜 그리고 어떻게 실행할 수 있습니까?


55

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. 이를 실행하면 세그먼테이션 오류가 발생했습니다 . :-/


다음 답변에 덧붙여, 공유 라이브러리에서 x 비트를 설정하면 r 비트가 지워져도 실행 파일에서 x 비트를로드 할 수 있었을 것입니다. 한때 시스템 실행 파일과 라이브러리에서 세계의 r 비트를 추방하는 것이 좋은 보안 관행으로 간주되었습니다. 광범위한 오픈 소스로 인해 이것은 익명 ftp 디렉토리의 / bin / ls에만 더 이상 적용됩니다. 나에게 x 비트 세트를 남겨 두는 것은 그 옛날 관행의 얼굴처럼 보입니다.
Joshua

답변:


52

이 라이브러리에는 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을 봐야합니다.


1
좋은 답변, 감사합니다! :-) nm공유 라이브러리에서 사용하려고 시도했지만 디버그 버전이 아닙니다. 그렇다면 왜 libvlc그리고 다른 사람들은 추락합니까?
Ho1

1
대부분의 공유 라이브러리는 실행 가능하지 않기 때문에 GNU libc는 예외입니다.
goldilocks

나는 두 사람을 발견 ld하고 libpthread.
Ho1

@ Ho1 ld.so은 다른 방식으로 특별합니다. 어느 정도까지는 동적으로 연결된 일반 실행 파일보다 실제 실행 파일에 가깝습니다.
Random832

1
위의 옵션은 실행 가능 공유 라이브러리를 작성하더라도 일부 실행 파일이이 링크를 시도 할 때 오류를 표시한다는 의미에서 불완전합니다. 자세한 샘플 참조는 여기에 추가 : unix.stackexchange.com/a/479334/152034
parasrish

21

github의 임의 glibc repo에서 답을 찾으십시오. 이 버전은 파일에“배너”를 제공합니다 version.c.

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

그렇다면 링커 / 컴파일러는 이것이 정확히 진입 점 기능이라는 것을 어떻게 알 수 있습니까?

makefile 으로 뛰어 들자 . 링커 플래그에는 흥미로운 플래그가 있습니다.

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

라이브러리에서 진입 점을 설정하기위한 링커 플래그입니다. 라이브러리를 빌드 할 때 -e function_name링커에서 실행 가능 동작을 제공 할 수 있습니다 . 실제로 무엇을합니까? 매뉴얼을 살펴 봅시다 (일부 날짜는 있지만 여전히 유효합니다) .

링커 명령 언어에는 출력 파일 (시작점)에서 첫 번째 실행 가능 명령을 정의하기위한 명령이 포함되어 있습니다. 인수는 심볼 이름입니다.

ENTRY (기호)

기호 할당과 마찬가지로 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;

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

시작 = other_symbol;

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

실제로 ld링커는 명령 줄 옵션 -e(가장 실용적인 솔루션)을 제공 start하거나 함수 symbol을 제공 하거나 어셈블러에 심볼 주소를 삽입 하면 진입 점 기능으로 실행 파일을 만듭니다 .

그러나 다른 링커와 함께 작동한다고 보장되지는 않습니다 (llvm의 lld에 동일한 플래그가 있는지 모르겠습니다). 이것이 파일에 정보를 제공하는 것 이외의 목적으로 유용한 이유는 무엇입니까?


1
파이썬이라면 단위 테스트를 제공합니다.
Erik Aronesty
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.