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?
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.