source

Linux 정적 라이브러리에서 기호 제한

manycodes 2023. 10. 23. 21:58
반응형

Linux 정적 라이브러리에서 기호 제한

Linux 정적 라이브러리(아카이브)로 내보내는 C 심볼의 수를 제한하는 방법을 찾고 있습니다.도서관 공식 API에 포함된 기호들로만 제한하고 싶습니다.저는 이미 'static'을 사용하여 대부분의 함수를 static으로 선언하지만, 이는 파일 범위로 제한합니다.도서관으로 범위를 제한하는 방법을 찾고 있습니다.

Ulrich Drepper의 How to Write Shared Libraries의 기법을 사용하여 공유 라이브러리에 대해 이 작업을 수행할 수 있지만 정적 아카이브에는 이 기법을 적용할 수 없습니다.그는 그의 초기 도서관 설계 모범 사례 논문에서 다음과 같이 쓰고 있습니다.

유일한 방법은 'ld -r'을 사용하여 특정 내부 자원이 필요한 모든 객체 파일을 하나로 결합한 다음 이 결합된 객체 파일이 내보내는 기호를 제한하는 것입니다.GNU 링커는 이것만 할 수 있는 옵션이 있습니다.

이 옵션들이 무엇인지 알아낼 수 있도록 도와줄 수 있는 사람?strip -w -K prefix_*'로 어느 정도 성공을 거두었지만, 이는 잔인하게 느껴집니다.이상적으로는 GCC 3, 4와 같이 사용할 수 있는 솔루션을 원합니다.

감사합니다!

나는 GNUld가 그러한 선택권을 가지고 있다고 생각하지 않습니다; Ulrich가 의미한 것이 틀림없습니다.objcopy, 다음과 같은 많은 옵션이 있습니다.--localize-hidden,--localize-symbol=symbolname,--localize-symbols=filename.

--localize-hidden특히 어떤 기호들이 노출되는지에 대한 아주 세밀한 통제를 할 수 있게 해줍니다.고려 사항:

int foo() { return 42; }
int __attribute__((visibility("hidden"))) bar() { return 24; }

gcc -c foo.c
nm foo.o
000000000000000b T bar
0000000000000000 T foo

objcopy --localize-hidden foo.o bar.o
nm bar.o
000000000000000b t bar
0000000000000000 T foo

그렇게bar()더 이상 개체에서 내보내지 않습니다(이 개체가 여전히 존재하여 디버깅에 사용 가능하더라도).제거할 수도 있습니다.bar()다같이objcopy --strip-unneeded.

정적 라이브러리는 GCC 3.x 또는 4.x로 컴파일된 코드에 대해 원하는 작업을 수행할 수 없습니다.

공유 개체(라이브러리)를 사용할 수 있다면 GNU 링커는 버전 스크립트라는 기능으로 필요한 작업을 수행합니다.일반적으로 버전별 진입점을 제공하는 데 사용되지만, 퇴화된 경우는 버전 지정 없이 공용 기호와 개인 기호를 구분할 뿐입니다.버전 스크립트는 --version-script= 명령줄 옵션을 지정하여 지정합니다.

입력 지점을 공개로 만들고 다른 모든 인터페이스를 숨기는 버전 스크립트의 내용:

{ global: foo; bar; local: *; };

http://sourceware.org/binutils/docs/ld/VERSION.html#VERSION 에서 이전 문서 참조

저는 공유 도서관의 열렬한 옹호자이고, 세계의 가시성을 제한하는 이러한 능력은 그들의 큰 장점 중 하나입니다.

Solaris(행복한 기억의 그렉 나히모프스키)를 위해 작성된 공유 객체의 이점을 더 많이 제공하는 문서는 http://developers.sun.com/solaris/articles/linker_mapfiles.html 에 있습니다.

도움이 되었으면 좋겠습니다.

이 답변의 장점은 정적 라이브러리를 사용하는 이유에 따라 달라집니다.링커가 사용하지 않는 개체를 나중에 삭제할 수 있도록 하려면 추가할 것이 별로 없습니다.조직화를 목적으로 하는 경우(응용프로그램을 연결하기 위해 전달해야 하는 개체의 수를 최소화하는 경우), 고용된 러시아인의 답변을 확장하는 것이 유용할 수 있습니다.

컴파일 시 컴파일 단위 내의 모든 심볼의 가시성은 다음을 사용하여 설정할 수 있습니다.

-fvisibility=hidden
-fvisibility=default

이는 하나의 파일 인터페이스를 컴파일할 수 있음을 의미합니다.c"는 기본 가시성과 숨겨진 가시성을 가진 더 많은 수의 구현 파일을 포함하며 소스에 주석을 달지 않습니다.그런 다음 재배치 가능한 링크는 비 api 함수가 "숨겨진" 단일 객체 파일을 생성합니다.

ld -r interface.o implementation0.o implementation1.o -o relocatable.o

이제 결합된 객체 파일은 Objcopy 대상이 될 수 있습니다.

objcopy --localize-hidden relocatable.o mylibrary.o

따라서 우리는 오직 의도된 API만을 노출하는 "library" 또는 "module" 하나의 객체 파일을 가지고 있습니다.


위 전략은 링크 시간 최적화와 적절히 상호작용합니다.-flto로 컴파일하고 컴파일러를 통해 링커에 -r을 전달하여 재배치 가능한 링크를 수행합니다.

gcc -fuse-linker-plugin -flto -nostdlib -Wl,-r {objects} -o relocatable.o

objcopy를 사용하여 이전과 같이 숨겨진 기호의 위치를 지정한 다음 linker를 마지막 시간에 호출하여 local 기호와 lto 후 객체에서 찾을 수 있는 다른 데드 코드를 제거합니다.안타깝게도 relocateable.o는 관련 정보를 모두 보유하고 있지 않을 것으로 보입니다.

gcc -nostdlib -Wl,-r,--discard-all relocatable.o mylibrary.o

lto의 현재 구현은 재배치 가능한 링크 단계에서 활성화된 것으로 보입니다.lton을 사용하면 hidden=>local 기호가 최종 재배치 가능 링크에 의해 제거됩니다.lto가 없으면 hidden=>local 기호가 최종 재배치 가능 링크에서 살아남았습니다.

lto의 향후 구현은 재배치 가능한 링크 단계를 통해 필요한 메타데이터를 보존할 가능성이 있는 것으로 보이지만, 현재 재배치 가능한 링크의 결과는 일반적인 오래된 객체 파일로 보입니다.

Employed Russian과 Jon Chesterfield의 답변을 개선한 것으로, 동적 라이브러리와 정적 라이브러리를 모두 생성하는 경우 도움이 될 수 있습니다.

DSO(lib의 동적 버전)에 기호를 숨기기 위한 표준 메커니즘부터 시작합니다.다음으로 모든 파일을 컴파일합니다.-fvisibility=hidden. API를 정의하는 헤더 파일에서 공개할 클래스와 함수의 선언을 변경합니다.

   #define DLL_PUBLIC __attribute__ ((visibility ("default")))
   extern DLL_PUBLIC int my_api_func(int);

자세한 내용은 여기를 참조하십시오.이것은 C와 C++ 둘 다에게 효과가 있습니다.DSO의 경우는 이 정도면 충분하지만 정적 라이브러리의 경우에는 다음과 같은 빌드 단계를 추가해야 합니다.

ld -r obj1.o obj2.o ... objn.o -o static1.o
objcopy --localize-hidden static1.o static2.o
ar -rcs mylib.a static2.o

ar단계는 선택 사항입니다. 링크를 연결할 수 있습니다.static2.o.

내 방식은 INTERNAL과 함께 내보내지 않는 모든 것을 표시하고 모든 .h 파일 보호, -DINNERTAL=로 컴파일 개발 빌드, -DINNERTAL=static으로 다른 모든 라이브러리 .c 파일을 포함하는 단일 .c 파일로 컴파일 릴리스 빌드를 표시하는 것입니다.

언급URL : https://stackoverflow.com/questions/393980/restricting-symbols-in-a-linux-static-library

반응형