android error dynamically loading libc++.so native library

8

I am trying to build a proof-of-concept android application which uses OpenSSH code to establish a SSH session with a server.

For that I am using android sources to build the required libraries and then pull them up to an AndroidStudio native project where everything should be packed and installed on the device.

However, one of the libraries (libc++.so) is failing to load dynamically on the device with the message "java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__register_atfork" referenced by "libc++.so"..."

This error is being thrown when loading libc++.so library from MainActivity java code (I am now loading one library at a time to be sure where it fails):

public class MainActivity extends AppCompatListActivity implements OnHostStatusChangedListener {
    ...................
    static {
        System.loadLibrary("dl");
        System.loadLibrary("c");
        System.loadLibrary("m");
        System.loadLibrary("c++"); // <--- Error dlopen failed: cannot locate symbol "__register_atfork" referenced by "libc++.so
        System.loadLibrary("ssh");
        System.loadLibrary("vrx-native");
    }
    .............
}

My interpretation of the error message is that symbol __register_atfork required by libc++.so is not defined by any of the other libraries. But examining the libraries symbol tables I dont see why dlopen fails to recognize the symbol being defined on libc.so:

$readelf -s libc++.so
Symbol table '.dynsym' contains 2367 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     .....................
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND __register_atfork@LIBC (2) <-- Undefined symbol reference
     .....................

$readelf -s libc.so
Symbol table '.dynsym' contains 1505 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     .............
    62: 00043509   120 FUNC    GLOBAL DEFAULT   13 __register_atfork@@LIBC
    ..............
    7518: 00043509   120 FUNC    GLOBAL DEFAULT   13 __register_atfork <-- symbol defined and exported by libc.so!!!

Examining the header and dynamic section of the libraries also does not provide any clue as to why this might be failing:

$ readelf -hd libc++.so
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          52 (bytes into file)
  Start of section headers:          573972 (bytes into file)
  Flags:                             0x5000200, Version5 EABI, soft-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         9
  Size of section headers:           40 (bytes)
  Number of section headers:         29
  Section header string table index: 28

Dynamic section at offset 0x8abf8 contains 29 entries:
  Tag        Type                         Name/Value
 0x00000003 (PLTGOT)                     0x8dfe8
 0x00000002 (PLTRELSZ)                   8216 (bytes)
 0x00000017 (JMPREL)                     0x2d738
 0x00000014 (PLTREL)                     REL
 0x6000000f (Operating System specific: 6000000f)        0x2b280
 0x60000010 (Operating System specific: 60000010)        0x24b8
 0x00000013 (RELENT)                     8 (bytes)
 0x6ffffffa (RELCOUNT)                   397
 0x00000006 (SYMTAB)                     0x21a0
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000005 (STRTAB)                     0xb590
 0x0000000a (STRSZ)                      107756 (bytes)
 0x00000004 (HASH)                       0x25a7c
 0x00000001 (NEEDED)                     Shared library: [libdl.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so]
 0x00000001 (NEEDED)                     Shared library: [libm.so]
 0x0000000e (SONAME)                     Library soname: [libc++.so]
 0x0000001a (FINI_ARRAY)                 0x8b3c0
 0x0000001c (FINI_ARRAYSZ)               4 (bytes)
 0x00000019 (INIT_ARRAY)                 0x8dbf4
 0x0000001b (INIT_ARRAYSZ)               4 (bytes)
 0x0000001e (FLAGS)                      BIND_NOW
 0x6ffffffb (FLAGS_1)                    Flags: NOW
 0x6ffffff0 (VERSYM)                     0x29f94
 0x6ffffffc (VERDEF)                     0x2b214
 0x6ffffffd (VERDEFNUM)                  1
 0x6ffffffe (VERNEED)                    0x2b230
 0x6fffffff (VERNEEDNUM)                 2
 0x00000000 (NULL)                       0x0

$ readelf -hd libc.so
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          52 (bytes into file)
  Start of section headers:          757116 (bytes into file)
  Flags:                             0x5000200, Version5 EABI, soft-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         10
  Size of section headers:           40 (bytes)
  Number of section headers:         33
  Section header string table index: 30

Dynamic section at offset 0x8232c contains 27 entries:
  Tag        Type                         Name/Value
 0x00000003 (PLTGOT)                     0x835bc
 0x00000002 (PLTRELSZ)                   5232 (bytes)
 0x00000017 (JMPREL)                     0x105c4
 0x00000014 (PLTREL)                     REL
 0x00000011 (REL)                        0xd85c
 0x00000012 (RELSZ)                      11624 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x6ffffffa (RELCOUNT)                   1304
 0x00000006 (SYMTAB)                     0x1c0
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000005 (STRTAB)                     0x5fd0
 0x0000000a (STRSZ)                      17483 (bytes)
 0x00000004 (HASH)                       0xa41c
 0x00000001 (NEEDED)                     Shared library: [libdl.so]
 0x0000000e (SONAME)                     Library soname: [libc.so]
 0x00000019 (INIT_ARRAY)                 0x83304
 0x0000001b (INIT_ARRAYSZ)               36 (bytes)
 0x0000001a (FINI_ARRAY)                 0x83328
 0x0000001c (FINI_ARRAYSZ)               4 (bytes)
 0x0000001e (FLAGS)                      BIND_NOW
 0x6ffffffb (FLAGS_1)                    Flags: NOW
 0x6ffffff0 (VERSYM)                     0xcbc4
 0x6ffffffc (VERDEF)                     0xd788
 0x6ffffffd (VERDEFNUM)                  5
 0x6ffffffe (VERNEED)                    0xd82c
 0x6fffffff (VERNEEDNUM)                 1
 0x00000000 (NULL)                       0x0

Any help appreciated

Update: Investigating the meaning of (2) on __register_atfork@LIBC (2)

Checking readelf sources we can see the (2) token is being printed from:

if (version_string)
{
    if (sym_info == symbol_undefined)
    printf ("@%s (%d)", version_string, vna_other);
else
    printf (sym_info == symbol_hidden ? "@%s" : "@@%s",
    version_string);
}

vna_other is being loaded from struct Elf32_External_Sym, member st_other...

typedef struct {
  unsigned char st_name[4];             /* Symbol name, index in string tbl */
  unsigned char st_value[4];            /* Value of the symbol */
  unsigned char st_size[4];             /* Associated symbol size */
  unsigned char st_info[1];             /* Type and binding attributes */
  unsigned char st_other[1];            /* No defined meaning, 0 */
  unsigned char st_shndx[2];            /* Associated section index */
} Elf32_External_Sym;

ELF specification states (on page 32):

st_other This member currently holds 0 and has no defined meaning.

Maybe this has some special meaning on ARM? No, this document does not define anything arm-specific for st_other...

Update: Investigating the meaning of st_other in the ELF file definition

Found this post titled Request to extend symbol visibilities (st_other)

Symbol visibility is currently represented by the least significant 2 bits of a symbol's st_other field.

The post mentions the visibility attributes that currently goes into st_other...

#define STV_DEFAULT     0
#define STV_INTERNAL    1
#define STV_HIDDEN      2
#define STV_PROTECTED   3

...and proposes two new visibility attributes...

#define STV_SINGLETON   4
#define STV_ELIMINATE   5

It seems (2) on readelf symbol table output corresponds to STV_HIDDEN attribute on the symbol st_other member...

android
c++
java-native-interface
native
asked on Stack Overflow Apr 25, 2016 by Adriano Gominho • edited Apr 27, 2016 by Adriano Gominho

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0