2009-12-04 3 views
7

타사 정적 라이브러리의 함수를 사용하는 공유 라이브러리를 만들려고합니다. 예를 들어, foobarlibfoobar.a입니다. 내 주요 응용 프로그램도 foo을 사용하고 해당 기호를 내보낼 것입니다 알아요. 따라서 간단히 bar에 링크하여 코드 크기를 저장하고 'foo'를 해결하지 않은 채로 남겨두기를 원합니다 (주 응용 프로그램에서 제공됨). libfoobar.a을 포함하면 링커 ld에 내 공유 라이브러리에 두 기능이 모두 포함됩니다. libfoobar.a을 포함하지 않으면 응용 프로그램 자체가 bar에 연결되어 있지 않기 때문에 내 라이브러리는 bar 기능에 액세스 할 수 없습니다. 질문 :라이브러리 함수의 선택적 정적 연결 공유 라이브러리

  • 공유 라이브러리를 구축 할 때에만 LD에게 특정 문자를 해결할 수있는 방법이 있나요?
  • libfoobar.a을 공유 라이브러리로 설정 하시겠습니까?
  • bar (libfoobar.a)의 파일을 추출하고 링커 줄에 지정 하시겠습니까?
  • 걱정하지 마십시오. bar의 복사본이로드되지 않도록 런타임 로더가 응용 프로그램에서 bar을 사용합니까?

답변

4

다음 사항 내가 제기 한 질문에 대답을 시도 :

  • LD 당신이 정적 라이브러리에서 특정 문자에 연결 생략하는 것을 허용하지 않는 것 같습니다. --just-symbols 또는 --undefined (또는 EXTERN 링커 스크립트 명령)을 사용하면 ld이 기호를 연결하지 못하게 할 수 없습니다.
  • 공유 하나, libfoobar.so.1.0에 정적 라이브러리, libfoobar.a 을 변환하고, 보이는 모든 문자를 수출합니다. --version-script 및 다른 방법을 사용하여 심볼의 하위 집합 만 내보낼 수도 있습니다.

    ld -shared -soname libfoobar.so.1 -o libfoobar.so.1.0 --whole-archive libfoobar.a --no-whole-archive

  • 그것은 당신이 관리 할 필요가 내부 종속성이있을 수 있기 때문에이를 추출하는 것보다 더 나은 당신의 정적 라이브러리의 사본에서 아카이브 멤버를 삭제합니다. 예를 들어 모든 심볼을 내보내는 경우 기본 실행 파일에서 맵 파일을 생성 할 수 있습니다. 그런 다음 실행 파일이 정적 라이브러리 사본에서 가져온 모든 아카이브 구성원을 grep하여 사본에서 삭제할 수 있습니다. 따라서 DSO가 정적 라이브러리에 링크되어 있으면 동일한 기호가 미해결 상태로 남습니다.

  • --pie 옵션을 사용하여 실행 파일을 컴파일하면 주 실행 파일을 DSO의 공유 라이브러리로 지정할 수 있습니다. DSO는 링크 명령의 정적 라이브러리보다 먼저 실행 파일을 링크합니다. 주의 할 점은 주 실행 파일은 LD_LIBRARY_PATH 또는 -rpath을 통해 사용할 수 있어야한다는 것입니다. 또한 strace을 사용하면 실행 파일이 라이브러리의 종속성이므로 DSO가로드 될 때 다시로드됩니다.

    ld -shared -rpath '$ORIGIN' -L. -lc -ldl -o DSO.so DSO.o app libfoobar.a

  • 동적 링커는 RTLD_DEEPBIND 플래그 foo는 먼저 dlopen을 호출하지 않는 한()의 실행 파일의 버전을 사용합니다. strace을 사용하면 전체 DSO가 mmap2()을 메모리에 매핑 된 파일임을 알 수 있습니다. 그러나 Wikipedia는 mmap에 대해 "디스크에서 실제로 읽는 것은 특정 위치에 액세스 한 후"게으른 "방식으로 수행됩니다." 이것이 사실이면 복제본 foo이로드되지 않습니다. 재정의는 DSO 으로 내 보낸 경우에만 발생합니다. foo. 그렇지 않으면 DSO가 정적으로 연결된 DSO가 foo 일 때마다 foo이 사용됩니다. 결론적으로

, 의 mmap()가 게으른 읽기를 사용하는 경우, 다음 가장 좋은 방법은 일반적인 방식으로 DSO를 연결하고 동적 링커와 리눅스가 알아서하도록하는 것입니다.

1

저는 공유 라이브러리에 대한 가장 큰 전문가가 아니므로 여기에 잘못되었을 수 있습니다!

내가하려는 일에 대해 맞춰 보면 libc.so와 공유 라이브러리를 연결하기 만하면됩니다. 라이브러리에 sscanf를 추가로 복사하고 싶지는 않습니다.

답변에 관심이있는 경우에 대비하여 내가 무엇을보고 있는지 알기 전에 귀하의 질문에 답변했습니다.

공유 라이브러리를 만들 때 특정 기호 만 해결하도록 ld에 지시하는 방법이 있습니까?

정적이 아닌 외부 함수 및 변수 만 공유 라이브러리의 기호 테이블에 있습니다.

공유 라이브러리를 빌드 할 때 링커 명령 행에서 객체에없는 기호는 확인되지 않은 상태로 유지됩니다. 링커가 그것에 대해 불평하면 공유 libc에 대한 공유 라이브러리를 링크해야 할 것입니다. 다른 공유 라이브러리에 의존하는 공유 라이브러리를 가질 수 있으며 ld.so는 종속성 체인을 처리 할 수 ​​있습니다.

더 많은 담당자가 있다면 나는 이것을 주석으로 묻습니다 : 맞춤형 버전의 sprintf/sscanf가 있습니까? 또는 공유 라이브러리가 -lc에서 구현을 사용하도록해도 괜찮습니까? -lc가 괜찮 으면 나의 대답은 아마 당신의 문제를 해결할 것이다. 그렇지 않다면 필요한 함수 만 가진 객체로 공유 라이브러리를 만들어야합니다. 즉 /usr/lib/libc.a에 링크하지 마십시오.

아마 나는 당신의

libc.a (실제로 "진짜"libc의) 선으로 혼란스러워지고 있어요. /usr/lib/libc.a는 정말 glibc (리눅스에서)입니다. libc.so에있는 동일한 코드의 정적 링크 된 복사본입니다. 자신의 libc.a (내가 처음에 생각한 것)에 대해 이야기하지 않는다면 ...

libc.a를 공유 라이브러리로 전환 하시겠습니까? 위치 독립적 코드로 컴파일되지 않았기 때문에 아마 그렇게 할 수는 있지만 할 수는 없으므로 런타임에 ld.so에 의해 많은 재배치가 필요합니다.

libc.a에서 sscanf를 추출하고 링커 행에 지정합니까?

가능합니다. ar t /usr/lib/libc.a를 사용하여 내용을 나열하십시오. (ar의 args는 tar와 비슷합니다 .tar는 테이프 용 ar ... old school 유닉스입니다.) 아마도 sscanf는 .a에있는 다른 .o 파일의 기호에 의존하기 때문에 아마도 쉽지 않을 것입니다.

+0

libc 혼란에 죄송합니다. 나는 타사 정적 라이브러리를 의미하며 예제로 libc를 사용했습니다. 나는 이것을 명확히하기 위해 나의 질문을 수정하려고한다. – KlaxSmashing

1

수정 된 더 명확한 질문에 답하십시오.

일반적으로 공유 라이브러리의 요점은 여러 프로그램이 링크 할 수 있다는 것입니다. 따라서 메인 프로그램의 심볼을 필요한 함수에 사용하는 최적화는 메인 프로그램이 항상 (정적 라이브러리 또는 다른 방법을 통해) 그 심볼을 제공하는 경우에만 작동합니다. 이것은 보통 사람들이하고 싶은 것이 아닙니다.

몇 가지 작은 기능이라면 아마도 그렇게해야합니다. 아마도 함수에 대한 두 개의 코드 사본, 즉 shlib에있는 코드와 주 프로그램에있는 코드가있을 것이다. 코드 크기/I 캐시에 두 개의 복사본이 있다는 히트가 적거나 (또는 ​​적어도 거대하지 않은) 또는 자주 호출되지 않고 성능에 중요하지 않은 경우 걱정할 사항이 아닙니다. (번역 : 나는 그것을 머리의 꼭대기에서 피하는 방법을 모른다. 그래서 그것을 보면서 그것을 피하는 더 복잡한 Makefile을 만들지는 않을 것이다.)

다른 대답을 참조하십시오. 정적 라이브러리에서 물건을 추출하기 위해 ar을 어지럽히는 것에 대한 몇 가지 코멘트가 있습니다. 요약 : .a에있는 여러 .o 파일 간의 종속성을 알지 못하기 때문에 별다른 문제가 아닐 수 있습니다.

공유 라이브러리가 정적 라이브러리에서 가져온 심볼을 내보내도록함으로써 원하는 것을 수행 할 수 있습니다. 그런 다음 기본 응용 프로그램을 링크 할 때 링커 명령 행에서 정적 라이브러리 앞에 공유 라이브러리를 놓습니다. ld는 shlib에서 "foo"를 찾아 그 사본을 사용합니다 (이 재수출 트릭이 가능한 경우). 그러나 "bar"의 경우 정적 lib의 복사본을 포함해야합니다.

ld --export-dynamic은 동적 기호 테이블의 모든 기호를 내보내는 데 필요할 수 있습니다. 시도해 봐. docs/man 페이지에서 "export"를 검색하십시오. "내보내기"는 라이브러리에서 기호를 볼 수있게 해주는 특수 용어입니다. --export-all-symbols은 i386 PE (Windows DLL) 섹션에 있습니다. 그렇지 않으면 아마 트릭을 수행 할 것입니다.

+0

ld 맨 페이지에서 뭔가 알 수 있습니다 : --just-symbols = filename : "파일 이름에서 심볼 이름과 그 주소를 읽지 만, 파일을 재배치하거나 출력에 포함하지 마십시오. 이렇게하면 출력 파일이 상징적으로 절대 위치를 참조 할 수 있습니다 다른 프로그램에 정의 된 메모리의. " –

+0

공유 라이브러리는 '플러그인'(항상로드되지는 않음)이므로 다른 코드, 특히 주 응용 프로그램에 대한 심볼을 제공 할 수 없습니다. 가장 쉬운 방법은 타사 정적 라이브러리를 동적 라이브러리로 변환하는 것입니다. – KlaxSmashing