Ld magically redefines statically related characters

For several days we have been dealing with a very strange problem.

I can’t understand how this happens - when a third-party program (MATLAB) uses our shared library, it somehow redefines some of our symbols (raising, to be precise) with its own. These characters are statically linked and (!!) local.

Here's the deal - we are using boost 1.47, MATLAB has increased 1.40. Currently, the library calls segfaults when called from our library to raise (regex).

So here is the magic:

  • We have no dependencies between libraries, 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)
  • No Cxx characters (our publicly available POC C characters for binary compatibility) are exported from our library, nm:
  nm -g --defined-only libmysharedlib.so

 addr1 T OurCSymbol1
 addr2 T OurCSymbol2
 addr3 T OurCSymbol3
 ...
  • However, he uses his momentum. AS? Stacktrace (tracks cut):
  [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: : 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

MATLAB is known to do dlopen only with the RTLD_NOW flag.

People, think with me, please. Now I am desperately trying not to fix this, but simply to understand the behavior of ld & elf.

edit: A small additional question: as I understand it, without special links, the characters in the linux.so libraries are never linked to? So even statically related local characters are allowed at runtime?

+4
source share
2 answers

Check the -Bsymbolic for ld .

If -Bsymbolic specified, then when creating a shared object, the ld object will try to bind global symbol references to definitions in the shared library. By default, it is used to defer binding to runtime.

This may be clearer with an example.

Say example.o contains a link to the global function defined in global.o ,

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

and the two common objects normal.so and symbolic.so constructed as follows:

 $ 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 

A normal.so code for normal.so shows that the globalfn call actually goes through the procedure binding table, and thus the final destination of the call is determined at runtime.

 $ objdump --disassemble normal.so ...snip... 00000194 <example>: ...snip... 1a6: e8 d9 ff ff ff call 184 < globalfn@plt > ...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 

Whereas in symbolic.so call always calls the definition of globalfn inside a shared object.

 $ 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. 
+5
source

Here's the deal - we are using boost 1.47, MATLAB has increased 1.40. Currently, the library calls segfaults when called from our library to raise (regex).

You invoke undefined behavior, which is "Doctor, it hurts when I do this." The Matlab executable already contains external functions for the boost::re_detail::perl_matcher< elided > . When Matlab loads your shared library, the dynamic linker sees that your shared library defines the same characters in a way that contradicts existing definitions. undefined.

The solution is to create a version of your library for use with Matlab that uses the same Boost version as Matlab.

+3
source

Source: https://habr.com/ru/post/1369119/


All Articles