2011-08-26 5 views
4

며칠 동안 우리는 매우 이상한 문제를 다루고 있습니다.Ld는 정적으로 링크 된 심볼을 마술처럼 오버라이드합니다.

제 3 자 (MATLAB) 프로그램이 우리의 공유 라이브러리를 사용할 때, 어떻게 든 우리의 기호 (부스트, 정확함)를 자신의 것으로 대체합니다. 그 기호는 정적으로 링크되어 있으며 (!!) 로컬입니다.

여기 거래가 있습니다. 우리는 부스트 1.47을 사용하고, MATLAB은 부스트 ​​1.40을 사용합니다. 현재 라이브러리 호출은 seurfault를 호출하여 OUR 라이브러리에서 부스트 (regex)를 호출합니다.

그래서, 여기에 마법 : 우리는 더 라이브러리 의존성이 없다

  • 는, LDD :
 
    linux-vdso.so.1 => (0x00007fff4abff000) 
    libpthread.so.0 => /lib/libpthread.so.0 (0x00007f1a3fd65000) 
    libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f1a3fa51000) 
    libm.so.6 => /lib/libm.so.6 (0x00007f1a3f7cd000) 
    libgomp.so.1 => /usr/lib/libgomp.so.1 (0x00007f1a3f5bf000) 
    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00007f1a3f3a8000) 
    libc.so.6 => /lib/libc.so.6 (0x00007f1a3f024000) 
    /lib64/ld-linux-x86-64.so.2 (0x00007f1a414f9000) 
    librt.so.1 => /lib/librt.so.1 (0x00007f1a3ee1c000) 
  • 없음 CXX 기호 (우리의 공공 상징 바이너리 호환성에 대한 POC C) Google 라이브러리에서 내보내집니다. nm :
  • 여전히 부스트 기능을 사용합니다. 방법? 스택 트레이스 (경로가 절단) : MATLAB은 RTLD_NOW 플래그 만 함께한다면 dlopen 않습니다
 
[ 0] 0x00007f21fddbb0a9 bin/libmwfl.so+00454825 fl::sysdep::linux::unwind_stack(void const**, unsigned long, unsigned long, fl::diag::thread_context const&)+000009 
[ 1] 0x00007f21fdd74111 bin/glnxa64/libmwfl.so+00164113 fl::diag::stacktrace_base::capture(fl::diag::thread_context const&, unsigned long)+000161 
[ 2] 0x00007f21fdd7d42d bin/glnxa64/libmwfl.so+00201773 
[ 3] 0x00007f21fdd7d6b4 bin/glnxa64/libmwfl.so+00202420 fl::diag::terminate_log(char const*, fl::diag::thread_context const&, bool)+000100 
[ 4] 0x00007f21fce525a7 bin/glnxa64/libmwmcr.so+00365991 
[ 5] 0x00007f21fb9eb8f0 lib/libpthread.so.0+00063728 
[ 6] 0x00007f21f3e939a9 libboost_regex.so.1.40.0+00342441 boost::re_detail::perl_matcher, std::allocator > >, boost::regex_traits > >::match_all_states()+000073 
[ 7] 0x00007f21f3eb6546 bin/glnxa64/libboost_regex.so.1.40.0+00484678 boost::re_detail::perl_matcher, std::allocator > >, boost::regex_traits > >::match_imp()+000758 
[ 8] 0x00007f21c04ad595 lib/libmysharedlib.so+04855189 bool boost::regex_match, std::allocator > >, char, boost::regex_traits > >(__gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator, boost::match_results, std::allocator > > >&, boost::basic_regex > > const&, boost::regex_constants::_match_flags)+000245 
[ 9] 0x00007f21c04a71c7 lib/libmysharedlib.so+04829639 myfunc2()+000183 
[ 10] 0x00007f21c01b41e3 lib/libmysharedlib.so+01737187 myfunc1()+000307 

그것은 알려져있다.

사람들, 나와 함께 생각해주세요. 이제이 문제를 해결하지 않아도되지만 ld & elf 동작을 이해하는 것이 절실합니다.

편집 : 작은 추가 질문 : 특별한 링커 옵션이 없으면 리눅스의 .so 라이브러리에있는 기호가 주소별로 연결되지 않은 것입니다. 따라서 정적으로 링크 된 로컬 심볼조차도 런타임에서 해결됩니까?

답변

5

에 대한 -Bsymbolic 옵션을 확인하십시오. -Bsymbolic가 지정되면

, 다음 공유 객체에게 LD를 만드는 시간에는 정의 공유 라이브러리 내의 에 전역 심볼에 대한 참조를 결합하려고 시도합니다. 기본값은 바인딩을 런타임에 지연하는 것입니다.

예를 들어 명확해질 수 있습니다. 으로 내장되어

example.oglobal.o에 정의 된 전역 함수에 대한 참조를 포함

,

$ nm example.o | grep ' U' 
    U _GLOBAL_OFFSET_TABLE_ 
    U globalfn 
$ nm global.o | grep ' T' 
00000000 T globalfn 

두 개의 공유 객체, normal.sosymbolic.so은 다음과 같습니다

$ cc -fPIC -c example.c 
$ cc -c global.c 
$ rm -f archive.a; ar cr archive.a global.o 
$ ld -shared -o normal.so example.o archive.a 
$ ld -Bsymbolic -shared -o symbolic.so example.o archive.a 

툴리스을 normal.so에 대한 코드는 globalfn이 실제로 프로 시저 연결 테이블을 통과하고 있으므로 이므로 호출의 최종 대상은 런타임에 결정됩니다. symbolic.so에있는 반면

$ objdump --disassemble normal.so 
...snip... 
00000194 <example>: 
...snip... 
1a6: e8 d9 ff ff ff   call 184 <[email protected]> 
...snip... 
$ readelf -r normal.so 

Relocation section '.rel.plt' at offset 0x16c contains 1 entries: 
Offset  Info Type   Sym.Value Sym. Name 
00001244 00000207 R_386_JUMP_SLOT 000001b8 globalfn 

는, 호출은 항상 공유 객체 내에서 globalfn의 정의를 호출합니다.

$ objdump --disassemble symbolic.so 
...snip... 
0000016c <shared>: 
...snip... 
17e: e8 0d 00 00 00   call 190 <globalfn> 
...snip... 
$ readelf -r symbolic.so 

There are no relocations in this file. 
+0

솔루션처럼 보입니다. 확인해 보겠습니다.)) Thx. 즉각적인 질문 - -Bsymbolic과 함께 MATLAB 기호를 무시하고 "대칭"segfault가 발생할 가능성이 있습니까? 우리 도서관의 모든 부스트 기호는 정보로 '지역 약점'입니다. – ALOR

+0

@ALOR'-Bsymbolic'은 링크 타임에 작업을 수행하고 "개체 내"참조가 해결되는 방식 만 변경합니다. 나는 이것을 명확히하기 위해 나의 대답 을 확장했다. – jkoshy

+0

Matlab에서 실제로 필요로하는 것을 제외하고'libmysharedlib.so'에있는 모든 기호 (특히 모든 부스트 기호)를 완전히 숨기려면 링커 버전 스크립트를 사용하는 것도 고려해야합니다. 이렇게하면 프로그램의 런타임로드 속도가 빨라지고 나중에로드 된 다른 라이브러리에 라이브러리가 영향을 미치지 않도록 할 수 있습니다. –

3

여기서 우리는 부스트 1.47을 사용하고, MATLAB은 부스트 ​​1.40을 사용합니다. 현재 라이브러리 호출은 seurfault를 호출하여 OUR 라이브러리에서 부스트 (regex)를 호출합니다.

정의가없는 동작을 호출합니다. "의사가이 상황을 앓을 때 아파"입니다. Matlab 실행 파일에는 이미 boost::re_detail::perl_matcher<elided> 클래스의 외부 함수가 포함되어 있습니다. Matlab이 공유 라이브러리를로드하면 동적 링커는 공유 라이브러리가 기존 정의와 충돌하는 방식으로 정확히 동일한 심볼을 정의한다는 것을 알게됩니다. 정의되지 않은 동작입니다.

해결 방법은 Matlab과 동일한 Boost 버전을 사용하는 Matlab 용 라이브러리 버전을 빌드하는 것입니다.

+0

동의합니다. 그러나 지옥에서 그는 심지어 지역의 상징을 만지는 이유는 무엇입니까? LD 문서는 분명하지 않습니다. 지금 올바르게 이해하면 RTLD_DEEPBIND가없는 지역 기호가 전역 기호로 대체 될 수 있습니까? – ALOR

+0

공유 라이브러리의 심볼이 "로컬"이라고 생각하게 만드는 이유는 무엇입니까? 적어도 일부는 그렇지 않습니다. –

+0

nm은 나를 그렇게 생각하게한다 :) 우리 public-C 인터페이스 함수들만이 전역 적이다 - 라이브러리는 -fvisibility = hidden으로 컴파일되고 인터페이스 함수는 gcc 속성 visibility = default를 가진다. – ALOR