2014-03-07 3 views
3

마지막 사용자와 관련이없는 심볼 이름을 숨기고 공유 또는 정적 라이브러리에서 API 만 볼 수있게하고 싶습니다.라이브러리의 심볼 이름 숨기기

int f_b1(){ 
return 21 ; 
} 

int f_b3(){ 
return f_b1() ; 
} 

나는 모든 방법이 __attribute__ ((visibility ("hidden")))static 데이터를 사용하여 같은 here을 언급하지만 성공적인 결과를 얻지 적용 : 그 같은 간단한 코드가 있습니다. 내 운영 체제는 우분투 및 x86_64 GNU/Linux 프로세서입니다. gcc로 컴파일 할 때 특별한 옵션을 사용합니까? nm 명령을 사용하여 라이브러리의 모듈 및 기능을 나열하고 있습니다. 위의 예에서 나는 단지 f_b3의 기능을 보이기를 원합니다. attribute hidden 매크로 컴파일러를 사용할 때 오류가 발생하지 않지만 함수가 여전히 nm 명령에 의해 출력 된 목록에 존재합니다.

답변

17

visibility("hidden") 특성 에서 오브젝트 파일을 억제하지 심볼을 수행하고 심볼 nm 의해 추출되는 것을 방지 할 수 없다. 은 동적 링커에게 심볼이 포함되어있는 공유 라이브러리 외부에서 심볼을 호출 할 수 없다고 지시합니다.

은 소스 파일 file.c이 예 기능을 포함 고려해

int f_b1(){ 
return 21 ; 
} 

int f_b3(){ 
return f_b1() ; 
} 

파일을 컴파일

gcc -c -o file.o file.c 

실행 nm file.o이 기호를 나열합니다. 출력 :

0000000000000000 T f_b1 
000000000000000b T f_b3 

기호에 대한 자세한 내용은 objdump -t file.o을 실행하십시오. 출력 : 여기에 우리가 f_b1f_b3.text 섹션에서 글로벌 (g) 함수 (F)는 것을 볼

file.o:  file format elf64-x86-64 

SYMBOL TABLE: 
0000000000000000 l df *ABS* 0000000000000000 file.c 
0000000000000000 l d .text 0000000000000000 .text 
0000000000000000 l d .data 0000000000000000 .data 
0000000000000000 l d .bss 0000000000000000 .bss 
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack 
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame 
0000000000000000 l d .comment 0000000000000000 .comment 
0000000000000000 g  F .text 000000000000000b f_b1 
000000000000000b g  F .text 000000000000000b f_b3 

.

지금과 같이 파일을 수정 : 다시

__attribute__((visibility ("hidden"))) int f_b1(void){ 
return 21 ; 
} 

__attribute__((visibility ("hidden"))) int f_b3(void){ 
return f_b1() ; 
} 

실행 objdump을 : 기호 f_b1f_b3 지금 .hidden 표시된다는 점을 제외하고

file.o:  file format elf64-x86-64 

SYMBOL TABLE: 
0000000000000000 l df *ABS* 0000000000000000 file.c 
0000000000000000 l d .text 0000000000000000 .text 
0000000000000000 l d .data 0000000000000000 .data 
0000000000000000 l d .bss 0000000000000000 .bss 
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack 
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame 
0000000000000000 l d .comment 0000000000000000 .comment 
0000000000000000 g  F .text 000000000000000b .hidden f_b1 
000000000000000b g  F .text 000000000000000b .hidden f_b3 

출력은 동일합니다. 그것들은 여전히 ​​외부 (전역) 링키지를 가지고 있으며,이를 포함하고있는 라이브러리 내의 다른 모듈로부터 예제를 위해 정적으로 호출 될 수 있지만 은 그 라이브러리 외부에서 동적으로 호출 될 수 없습니다. 같이 동적 연결에서 f_b1f_b3을 은폐하려는 경우

그래서하는 공유 라이브러리, 당신은 visibility ("hidden")를 사용할 수 있습니다.당신이 정적 라이브러리에 정적 연결에서 f_b1f_b3을 은폐하려는 경우

, 당신은 모든 것을 수행 할 visibility 속성을 사용할 수 없습니다.

정적 라이브러리의 경우 외부 연결 대신 내부에 을 부여하는 기호 만 "숨길"수 있습니다. 이를 수행하는 방법은 표준 static 키워드를 접두사로 사용하는 것입니다. 하지만 내부 연결은 기호가 인 경우에만 컴파일 단위로 표시됩니다. 다른 모듈에서 참조 할 수 없습니다. 그것은 링커가 전혀 사용할 수 없습니다. 이 같은 다시

수정 file.c :

static int f_b1(void){ 
return 21 ; 
} 

static int f_b3(void){ 
return f_b1() ; 
} 

그리고 다시 objump을 실행

file.o:  file format elf64-x86-64 

SYMBOL TABLE: 
0000000000000000 l df *ABS* 0000000000000000 file.c 
0000000000000000 l d .text 0000000000000000 .text 
0000000000000000 l d .data 0000000000000000 .data 
0000000000000000 l d .bss 0000000000000000 .bss 
0000000000000000 l  F .text 000000000000000b f_b1 
000000000000000b l  F .text 000000000000000b f_b3 
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack 
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame 
0000000000000000 l d .comment 0000000000000000 .comment 

당신은 f_b1f_b3 여전히 .text 섹션의 함수로보고되는 것을 볼 수 있지만 지금 (l)로 분류되며 글로벌이 아닙니다. 그것이 내부 연결입니다. 실행 nm file.o 출력은 다음과 같습니다 대신 'T'플래그 의 것을 제외

원본 파일과 동일
0000000000000000 t f_b1 
000000000000000b t f_b3 

, 우리가 지금 '를 t'플래그가 있습니다. 두 플래그는 기호가 .text 섹션에 있음을 의미하지만 'T'는 전역이고 't'는 로컬임을 나타냅니다.

분명히, nm이 (가) 번으로 표시된 파일을보고 싶다고 생각됩니다. 심볼이 file.o 인 경우 nm file.o이 심볼을보고하지만 그 존재 여부는 정적 또는 동적 연결에 대해 표시 여부와 관계가 없음을 이해해야합니다.

는 사라 함수 기호,합니다 (static 키워드로 여전히) 다시 한번 을 file.c를 컴파일 활성화 최적화 이번에 만들려면 :

gcc -c -O1 -o file.o file.c 

지금을 objdump 보고서 :

file.o:  file format elf64-x86-64 

SYMBOL TABLE: 
0000000000000000 l df *ABS* 0000000000000000 file.c 
0000000000000000 l d .text 0000000000000000 .text 
0000000000000000 l d .data 0000000000000000 .data 
0000000000000000 l d .bss 0000000000000000 .bss 
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack 
0000000000000000 l d .comment 0000000000000000 .comment 

f_b1f_b3은 사라지고 nm file.o은 전혀보고하지 않습니다. 왜? static은 컴파일러에게이 기호를 컴파일 할 파일 내에서 이라고 만 호출 할 수 있으므로 최적화는 거기에서 을 참조 할 필요가 없다고 결정합니다. 그래서 컴파일러은 오브젝트 코드에서 제거합니다. 그러나 그들이 최적화없이 링커에게 보이지 않았다면 최적화 할 수 없었습니다.

결론 : nm이 기호를 추출 할 수 있는지 여부는 중요하지 않습니다. 기호가 로컬/내부이면 정적 또는 동적으로 연결할 수 없습니다. 기호가 .hidden으로 표시되면 을 동적으로 링크 할 수 없습니다. visibility("hidden")을 사용하여 .hidden 기호를 표시 할 수 있습니다. 표준 static 키워드를 사용하여 로컬/내부 기호를 만드십시오.

+0

위대한 설명입니다. –

+0

오브젝트 파일 이름도 숨길 수 있습니까? 내'nm' 명령은 이와 같이 출력합니다. '''b.o : 0000000000000000 T는 f_b2 0000000000000010 T f_b3 c.o : '''나뿐만 아니라,'b.o 및 c.o' 이름을 숨길하고 싶습니다. 고마워 .. –

+2

예 : 'strip -s file.o'을 실행하십시오. 'man strip'을보세요. 모든 심볼을 제거하면 오브젝트 파일을 디버깅 할 수 없습니다. –

1

나는 이것이 이미 오래된 스레드라는 것을 알고 있습니다. 그러나 정적 링크에 대한 몇 가지 사실을 숨겨진 심볼을 로컬로 만드는 의미에서 공유하고 따라서 오브젝트 파일이나 정적 라이브러리의 (전역) 정적 연결에서 이러한 심볼을 방지하고 싶습니다. 이것은 심볼 테이블에서 보이지 않게하는 것을 의미하지는 않습니다. 정적 라이브러리에 정적 링크에서 f_b1 및 f_b3을 은폐하려는 경우

, 당신이 그렇게 할 가시성 속성을 사용할 수 없습니다

마이크 Kingham의 대답은 매우 유용하지만, 다음과 같은 세부 사항 완전하지 않습니다 조금도.

날 숨겨진 기호를 확실히 file.c의 간단한 코드의 예를 사용하고 Symbol hiding in static libraries built with Xcode/gccypsu의 대답을 적용하여 현지 할 수 있다는 것을 보여 드리겠습니다. 첫 번째 단계에서는 f_b1f_b3에 숨겨진 속성이 표시된 objdump 출력을 재생산합시다. 이것은 file.c에 숨겨진 속성을 모든 기능을 제공하는 다음 명령을 수행 할 수 있습니다

gcc -fvisibility=hidden -c file.c 

objdump -t file.o의 출력 마이크 Kingham에 의해 얻은이 정확히 같은 중간 결과

file.o:  file format elf64-x86-64 

SYMBOL TABLE: 
0000000000000000 l df *ABS* 0000000000000000 file.c 
0000000000000000 l d .text 0000000000000000 .text 
0000000000000000 l d .data 0000000000000000 .data 
0000000000000000 l d .bss 0000000000000000 .bss 
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack 
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame 
0000000000000000 l d .comment 0000000000000000 .comment 
0000000000000000 g  F .text 000000000000000b .hidden f_b1 
000000000000000b g  F .text 0000000000000010 .hidden f_b3 

제공합니다. 이제 hidden 속성이있는 심볼을 로컬로 만듭니다. 즉, 다음과 같이 binutils에서 objcopy을 사용하여 달성된다 :

objcopy --localize-hidden --strip-unneeded file.o 

가 objdump를 사용하여, 마찬가지로

file.o:  file format elf64-x86-64 

SYMBOL TABLE: 
0000000000000000 l d .text 0000000000000000 .text 
0000000000000000 l  F .text 000000000000000b .hidden f_b1 
000000000000000b l  F .text 0000000000000010 .hidden f_b3 
0000000000000000 l d .data 0000000000000000 .data 
0000000000000000 l d .bss 0000000000000000 .bss 
0000000000000000 l d .comment 0000000000000000 .comment 
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack 
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame 

부여 nm file.of_b1 비록

0000000000000000 t f_b1 
000000000000000b t f_b3 

주고 f_b3는 상기에서 여전히 볼 수 있습니다 기호 테이블 그들은 로컬 있습니다. 따라서 함수 f_b1f_b3은 정적 연결에서 숨겨집니다!

또한 함수를 정적으로 선언하고 기호 테이블에서 완전히 제거 할 수있는 메모를 추가하고 싶습니다. 첫째, 제거는 결정적으로 수행 할 수 있으며 컴파일러 최적화에 의존하지 않고 objcopy을 사용하여 수행 할 수 있습니다.

objcopy --strip-unneeded file.o 

정적 기능 f_b1f_b2file.o의 심볼 테이블에 더 이상 없습니다.

두 번째로,이 정적 함수를 심볼 테이블에서 사라지게하는 정적 사용은 단일 소스 파일 C 프로젝트에서만 작동합니다. C 프로젝트가 여러 구성 요소와 파일로 구성되는 즉시 모든 C 소스 및 헤더 파일을 하나의 단일 소스 파일로 병합하고 모든 내부 인터페이스 (함수)를 전역 변수를 제외하고 명백하게 선언하여 수행 할 수 있습니다 (상단) 인터페이스. 이것이 가능하지 않다면 원래 ypsu (그리고 아마도 많은 다른 것들 - 예를 들어 Restricting symbols in a Linux static library을보십시오)에 기술 된 방법으로 대체 될 수 있습니다.

0

MacOS/iOS의 경우 링커에는 심볼 표시를 제어하는 ​​몇 가지 추가 옵션이 있습니다. 확인 예컨대 자세한 내용

  • -[un|re]exported_symbols_list
  • -[un]exported_symbol

ld64 설명서 또는 모양이 here 있습니다.

관련 문제