Search code examples
clinuxshared-librariesld

Supress ld symbol not found error to resolve later in runtime


I have the following library:

shared4.c:

int get_another_int(void){
    return 10;
}

And the binary:

#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>

int get_another_int(void);

int main(void){
    void *handle = dlopen("/home/me/c/build/libshar4.so", RTLD_GLOBAL | RTLD_NOW);
    if(!handle){
        exit(EXIT_FAILURE);
    }
    printf("handle = %p\n", handle);
    printf("another_int = %d\n", get_another_int());
}

I did not link the binary with the library and added an ld option to ignore the symbol not found error:

-Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all

With such options the binary compiled and linked "fine".

The plt section looks as follows:

$ objdump -d -j .plt ./build/bin_shared 

./build/bin_shared:     file format elf64-x86-64


Disassembly of section .plt:

00000000000005e0 <.plt>:
 5e0:   ff 35 22 0a 20 00       pushq  0x200a22(%rip)        # 201008 <_GLOBAL_OFFSET_TABLE_+0x8>
 5e6:   ff 25 24 0a 20 00       jmpq   *0x200a24(%rip)        # 201010 <_GLOBAL_OFFSET_TABLE_+0x10>
 5ec:   0f 1f 40 00             nopl   0x0(%rax)
        ...

0000000000000600 <dlopen@plt>:
 600:   ff 25 1a 0a 20 00       jmpq   *0x200a1a(%rip)        # 201020 <dlopen@GLIBC_2.2.5>
 606:   68 00 00 00 00          pushq  $0x0
 60b:   e9 d0 ff ff ff          jmpq   5e0 <.plt>

0000000000000610 <__printf_chk@plt>:
 610:   ff 25 12 0a 20 00       jmpq   *0x200a12(%rip)        # 201028 <__printf_chk@GLIBC_2.3.4>
 616:   68 01 00 00 00          pushq  $0x1
 61b:   e9 c0 ff ff ff          jmpq   5e0 <.plt>

0000000000000620 <exit@plt>:
 620:   ff 25 0a 0a 20 00       jmpq   *0x200a0a(%rip)        # 201030 <exit@GLIBC_2.2.5>
 626:   68 02 00 00 00          pushq  $0x2
 62b:   e9 b0 ff ff ff          jmpq   5e0 <.plt>

I examined the objdump and noticed the following fragment of main:

 66b:   e8 a0 ff ff ff          callq  610 <__printf_chk@plt>
 670:   e8 7b ff ff ff          callq  5f0 <.plt+0x10>

But the application failed to start with the following error:

$ ./build/bin_shared 
./build/bin_shared: error while loading shared libraries: unexpected PLT reloc type 0x00

I looked at all relocation types:

$ objdump -R ./build/bin_shared 

./build/bin_shared:     file format elf64-x86-64

DYNAMIC RELOCATION RECORDS
OFFSET           TYPE              VALUE 
0000000000200dd8 R_X86_64_RELATIVE  *ABS*+0x00000000000007a0
0000000000200de0 R_X86_64_RELATIVE  *ABS*+0x0000000000000760
0000000000201040 R_X86_64_RELATIVE  *ABS*+0x0000000000201040
0000000000200fd8 R_X86_64_GLOB_DAT  _ITM_deregisterTMCloneTable
0000000000200fe0 R_X86_64_GLOB_DAT  __libc_start_main@GLIBC_2.2.5
0000000000200fe8 R_X86_64_GLOB_DAT  __gmon_start__
0000000000200ff0 R_X86_64_GLOB_DAT  _ITM_registerTMCloneTable
0000000000200ff8 R_X86_64_GLOB_DAT  __cxa_finalize@GLIBC_2.2.5
0000000000201020 R_X86_64_JUMP_SLOT  dlopen@GLIBC_2.2.5
0000000000201028 R_X86_64_JUMP_SLOT  __printf_chk@GLIBC_2.3.4
0000000000201030 R_X86_64_JUMP_SLOT  exit@GLIBC_2.2.5
0000000000000000 R_X86_64_NONE     *ABS*                    //<---- This relocation

Is there a way to workaround this and make symbols from a library loaded with dlopen, but not linked with ld during the link time to be available for dynamic linker so the application I showed above would run as expected?


Solution

  • Is there a way to workaround this

    The linker must know that the symbol will be coming from some shared library, and needs to know what kind of symbol this is, in order to properly build a dynamic symbol reference for that symbol in the main executable.

    Since you don't want to (or can't) provide libshar4.so at link time, your other option is to pretend that some other library that you do link against provides this symbol.

    For example, since you use dlopen, you could create a dlopen_stub.so, which provides both dlopen and get_another_int (the actual implementation of either function in the stub can be empty), set the SONAME of this stub library to libdl.so.2 (or whatever SONAME your real libdl.so uses), and link your binary with that stub (instead of linking with -ldl).

    At runtime, provided that LD_BIND_NOW is not in effect, the binary will not attempt to resolve get_another_int until after you've loaded libshar4.so, and by that time the symbol will be available.