Nito
Nito

Reputation: 51

Android dynamic linked library unable to resolve symbols of main program

I can succesfully create a program in C that links to a library, and is able to call functions of that library. If that library calls a function from the main program an error arises:

root@android:/data/local/tmp # ./helloworld                                    
link_image[1966]:   637 could not load needed library 'libhello.so' for './helloworld' (reloc_library[1315]:   637 cannot locate 'crossfunction'...) CANNOT LINK EXECUTABLE

The code is in two C files, and I also include the Makefile. hello.c is the library which holds the function hello which is called by main.c (the main program). The function hello tries to invoke the function crossfunction and that doesn't work in android (in Linux it works perfectly well). I suspect from the android linker, but have no proof so far (please see https://android.googlesource.com/platform/bionic/+/froyo-release/linker/README.TXT).

Another good hint might be the NOTYPE assignment in the readelf output for the crossfunction in the libhello.so file. Please see below.

         5: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND crossfunction

Any hints perhaps in the compiler flags or in linker flags?

::::::::::::::
main.c
::::::::::::::
#include <stdio.h>
extern void hello(const char* name);
int main(void) {
  hello("World!");
}

void crossfunction(void) {
  printf("This is called from the library\n");
}
::::::::::::::
hello.c
::::::::::::::
#include <stdio.h>
extern void crossfunction(void);
static char *s;      
void hello(const char* name) {
  s = "my second name";
  printf("Hello %s %s!\n", s, name);
  crossfunction();
}

To compile I use the agcc wrapper with the android ndk https://github.com/nitomartinez/agcc

Here is the Makefile:

OBJECTS=main.o
LIB=libhello.so
LIBOBJ=hello.o
TARGET=helloworld
TARGETDIR=/data/local/tmp
CC=agcc

.PHONY: all install run clean distclean

all: $(TARGET)  $(LIB)

hello.o: hello.c Makefile
    $(CC) $(CFLAGS) -c -o hello.o hello.c

$(TARGET): $(OBJECTS) $(LIB) Makefile
    $(CC) -Wl,-rpath=$(TARGETDIR)  -lhello -L . -o $(TARGET) $(OBJECTS)

$(LIB): $(LIBOBJ) Makefile
    $(CC) -shared -o $(LIB) $(LIBOBJ)

install: $(TARGET)
    adb push $(TARGET) $(TARGETDIR)/$(TARGET)
    adb push $(LIB) $(TARGETDIR)/$(LIB)

run: install
    adb shell "export LD_LIBRARY_PATH=$(TARGETDIR); $(TARGETDIR)/$(TARGET) "

I had a look at the readelf bits, but I found no substantial differences in the .dynsym, .rel.plt and .symtab sections.

For helloworld

Relocation section '.rel.plt' at offset 0x33c contains 3 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
0000954c  00000416 R_ARM_JUMP_SLOT   00008368   hello
00009550  00000516 R_ARM_JUMP_SLOT   00008374   puts
00009554  00000816 R_ARM_JUMP_SLOT   00008380   __libc_init

Symbol table '.dynsym' contains 16 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 000083b0    32 FUNC    GLOBAL DEFAULT    7 crossfunction
     2: 00008450     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_end
     3: 00009558     0 NOTYPE  GLOBAL DEFAULT  ABS _bss_end__
     4: 00008368     0 FUNC    GLOBAL DEFAULT  UND hello
     5: 00008374     0 FUNC    GLOBAL DEFAULT  UND puts
...
Symbol table '.symtab' contains 62 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
...
    41: 000083b0    32 FUNC    GLOBAL DEFAULT    7 crossfunction
    42: 00008450     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_end
    43: 00009558     0 NOTYPE  GLOBAL DEFAULT  ABS _bss_end__
    44: 00008368     0 FUNC    GLOBAL DEFAULT  UND hello
    45: 00008374     0 FUNC    GLOBAL DEFAULT  UND puts
...
    55: 00008390    32 FUNC    GLOBAL DEFAULT    7 main
...

And for libhello.so

Relocation section '.rel.plt' at offset 0xae8 contains 7 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
000032cc  00000516 R_ARM_JUMP_SLOT   00000000   crossfunction
000032d0  00000616 R_ARM_JUMP_SLOT   00000000   printf
000032d4  00000f16 R_ARM_JUMP_SLOT   00000000   __cxa_begin_cleanup
000032d8  00001516 R_ARM_JUMP_SLOT   00000000   memcpy
000032dc  00001f16 R_ARM_JUMP_SLOT   00000000   abort
...

Symbol table '.dynsym' contains 64 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
...
     5: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND crossfunction
     6: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf
...
    19: 00000b88   100 FUNC    GLOBAL DEFAULT    7 hello
    21: 00000000     0 FUNC    GLOBAL DEFAULT  UND memcpy
...

Symbol table '.symtab' contains 138 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
    25: 00000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
    79: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND crossfunction
    80: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf

Upvotes: 5

Views: 5177

Answers (1)

dragonroot
dragonroot

Reputation: 5841

From version 2.0 Android follows the RTLD_LOCAL shared library semantics. Meaning that the symbols in libraries are not available for subsequently loaded libraries. You have to turn your main program into a .so library and link that to libhelloworld.so explicitly. See this thread for more info.

Note that Android dynamic linker is different from the Linux one. Be sure to test your apps on emulators of different versions (starting from Api 3), as the mechanisms were changing over time.

Upvotes: 3

Related Questions