【问题标题】:Is it possible to hardcode shared library position in C program?是否可以在 C 程序中硬编码共享库位置?
【发布时间】:2012-12-30 17:00:57
【问题描述】:

通常,程序(在 Linux 中)使用 LD_LIBRARY_PATH 来定位它们的共享库,但我想使用自定义路径,而不是永久更改 LD_LIBRARY_PATH。

基本上,bash-wrapper 可以轻松实现:

#!/bin/sh
export LD_LIBRARY_PATH=/my_lib_path/
/my_bin_path/myprogram $*

(Bash 仅在此脚本中更改 LD_LIBRARY_PATH,而不是永久更改)

我想知道如果没有丑陋的 bash-hack,是否可以在纯 C 在一个可执行文件中 中做同样的事情。所有路径和库的确切名称在编译时都是已知的。

【问题讨论】:

    标签: c shared-libraries


    【解决方案1】:

    将-rpath 选项传递给ld,或者通过您的编译器-Wl,-rpath。它允许您扩展搜索路径。它通常由希望从某个插件目录加载模块的可执行文件使用。您可以通过此方法添加任意数量的目录。

    【讨论】:

      【解决方案2】:

      正如其他人所说,链接程序时,您可以使用-Wl,-rpath 将特定路径添加到应用程序的库搜索路径。但是,如果您只想硬编码特定库的路径,请在链接时使用该路径,而不是使用 -l 选项。例如,不用-lfoo,只需在链接命令行上使用/opt/foo/lib/libfoo.so.1。

      【讨论】:

      • gcc -o myprogram /mypath/mylibrary.so mysource.c 确实可以编译(所以我确定找到了共享对象),但是当我尝试运行程序时它仍然抱怨缺少库。我不太清楚你所说的“链接命令行”是什么意思。
      • chrtool 也可能令人感兴趣,它允许在链接后更改 RPATH - 尽管它有很多愚蠢的限制,因为它改变了路径并且不能再让它(或如果以前不存在,则添加一个)。
      • @Robby75:当您运行二进制文件时,mylibrary.so 是否存在于/mypath 中?关于mylibrary.so,readelf -a myprogram 向您展示了什么?
      【解决方案3】:

      您不能在运行时更改LD_LIBRARY_PATH,动态加载器会在程序执行时读取它一次并且不再检查它,您可以使用dlopen()来自己加载共享库:

      dlopen("/path/to/shared/lib.so", RTLD_LAZY);
      

      这仅在您加载库并在运行时使用dlsym() 来查找符号时才有效,否则如果您调用库中的函数,则必须在加载时解析这些引用,并且 AFAIK 您必须使用类似 bashscript 的东西.

      注意:如果您重新执行该过程,可以在运行时更改LD_LIBRARY_PATH,我刚刚对此进行了测试,它似乎可以工作,但它非常hackish,这可能是@987654326 中的唯一方法@:

      void *handle;
      // first time check if path is not set
      if (getenv("LD_LIBRARY_PATH")==NULL) {
          //set it and re-execute the process
          setenv("LD_LIBRARY_PATH", "/path/to/lib/", 1);
          execl(argv[0], argv[0], NULL);
      }
      // open the shared library the second time
      handle = dlopen("test.so", RTLD_LAZY);
      printf("%p\n", handle);
      dlclose(handle);
      

      【讨论】:

      • 这只有在你 dlopen 库时才有效,这是一个相对不可移植的事情。如果您愿意,请使用libltdl,它有一个lt_dladdsearchdir。
      • @Robby75 您使用dlsym() 查找符号并调用它,不确定这是否是您想要的,但这是我能想到的唯一方法。
      • 当心:我相信动态加载器在被调用时会读取 LD_LIBRARY_PATH (在程序正常运行之前)并忽略任何后续更改,因此程序内部的setenv() 可能不起作用 - 或者可能不起作用到处工作。
      • @JonathanLeffler 是的,这是真的,但是如果使用fork() 和exec() 重新执行该过程呢?
      • 我使用了一种技术,让进程查看其 LD_LIBRARY_PATH,并在需要时调整路径和 exec()s 本身。这只是实验软件; SUID root 程序还有其他问题需要处理。但它在其范围内发挥作用。
      【解决方案4】:

      我认为这在执行时是不可能的:在执行程序之前加载库...

      但是您可以在编译时通过将选项 -rpath 传递给您的链接器来实现

      【讨论】:

        猜你喜欢
        • 2021-09-24
        • 2010-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多