c - 抑制 ld symbol not found 错误以便稍后在运行时解决

标签 c linux shared-libraries ld

我有以下库:

shared4.c:

int get_another_int(void){
    return 10;
}

和二进制文件:

#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());
}

我没有将二进制文件与库链接,并添加了一个 ld 选项来忽略找不到符号的错误:

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

有了这些选项,二进制编译和链接就“正常”了。

plt 部分如下所示:

$ 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>

我检查了 objdump 并注意到了以下 main 片段:

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

但应用程序启动失败,出现以下错误:

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

我查看了所有重定位类型:

$ 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

有没有办法解决这个问题,并从加载了 dlopen 的库中创建符号,但在链接期间没有与 ld 链接以供使用动态链接器,以便我上面显示的应用程序能够按预期运行?

最佳答案

Is there a way to workaround this

链接器必须知道该符号将来自某个共享库,并且需要知道这是什么种类的符号,以便正确地构建动态主要可执行文件中该符号的符号引用。

由于您不想(或不能)在链接时提供 libshar4.so,您的另一个选择是假装链接提供这个符号。

例如,由于您使用 dlopen,您可以创建一个 dlopen_stub.so,它同时提供 dlopen get_another_int(stub中任一函数的实际实现都可以为空),将这个stub库的SONAME设置为libdl.so.2(或者你真正的 libdl.so 使用的任何 SONAME),并将你的二进制文件与该 stub 链接(而不是与 -ldl 链接) .

在运行时,假设 LD_BIND_NOW 生效,二进制文件将不会尝试解析 get_another_int,直到您加载 libshar4.so,届时符号将可用。

关于c - 抑制 ld symbol not found 错误以便稍后在运行时解决,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58162190/

相关文章:

c - 动态数组,传递地址

c - X86 32b 汇编 - 使用 atoll

从另一个 C 进程创建一个新的独立进程

linux - 处于断开连接状态的 Teamcity 构建代理

linux - 编写将文件复制到子文件夹的脚本

c++ - #including <iostream> 中断共享对象的链接

c++ - 混合 C/C++ 代码产生 "undefined symbol"与共享库

c - Linux - 为什么阻塞和忽略的信号处于待处理状态?

c - 如何在 linux C 的用户空间程序中找到 sigset_t 的补码

gcc - 如何使用内置的 rpath 构建和安装 gcc?