RPATH & $ORIGIN 你的库为什么找不到

Linux RPATH & $ORIGIN

许多现代C / C ++项目都利用Autotools创建GNU构建系统,例如 根据平台生成make文件。 可执行文件(二进制文件)在生成/编译过程中生成,并且可以在执行编译的计算机上本地执行。 但是,如果将同一可执行文件移动到另一台计算机上,或者只是移到同一台计算机上的其他文件夹,则在运行该可执行文件时可能会遇到“找不到库”错误。

什么是RPATH和$ORIGIN?

RPATH代表运行时搜索路径。 根据Wikipedia的说法,“rpath指定在可执行文件或库中硬编码的运行时搜索路径。 动态链接加载程序使用rpath查找所需的库” 动态链接是所需共享库的一种“惰性”链接,不是在编译阶段,而是在运行一个可执行文件的后期。 如果设置了rpath,覆盖或补充系统默认的共享库搜索路径,则共享库的路径将被编码到可执行文件的头中,就像扩展PATH系统变量链一样。

$ORIGIN是一个特殊的变量,指示实际的可执行文件名。它在运行时解析到可执行文件的位置,在设置RPATH时非常有用。

示例

编写libhello.so动态库文件

hello.h

#pragma once

void HelloFunc();

hello.cpp

#include <iostream>

void HelloFunc()
{
    std::cout << "hello function \n";
}

编译

➜ g++ -fPIC -shared -o libhello.so hello.c

main.c

#include <iostream>
#include "hello.h"
int main()
{
    HelloFunc();
    std::cout << "hello world \n";
    return 0;
}

正常编译

➜ g++ main.c -o main -L. -lhello

运行结果

./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

我们需要解决找到libhello.so的问题才可以使main运行起来,可以通过以下两种方式

  • export LD_LIBRARY_PATH=yourpath/lib
  • libhello.so拷贝到/usr/local/lib,然后运行ldconfig

使用RPATH

编译期

编译命令改为

➜ g++ main.c -o main -L. -lhello -Wl,-rpath='$ORIGIN/'

运行

➜./main 
hello function 
hello world 

程序正常运行

在编译之后,执行之前

  • 使用chrpath
chrpath -r "\$\ORIGIN/path/to/library" <executable>

如果之前没有为可执行文件设置rpath,上述命令可能会失败。使用patchelf实用程序尝试下面的命令,它不会抱怨没有设置rpath,并且会设置RUNPATH来实现类似的目标。

  • 使用patchelf
patchelf — set-rpath ‘$ORIGIN/path/to/library’ <executable>

如何检查RPATH的值?

有多种方法可以检查可执行文件或库的RPATH值。objdump、readelf和chrpath是3个常用的实用程序。

objdump -x path/to/executable | grep RPATH

或者

readelf -d path/to/executable | head -20

或者

chrpath -l path/to/executable

使用readelf结果

➜  hello readelf -d main | head -20   

Dynamic section at offset 0x2dd0 contains 29 entries:
  标记        类型                         名称/值
 0x0000000000000001 (NEEDED)             共享库:[libhello.so]
 0x0000000000000001 (NEEDED)             共享库:[libstdc++.so.6]
 0x0000000000000001 (NEEDED)             共享库:[libm.so.6]
 0x0000000000000001 (NEEDED)             共享库:[libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             共享库:[libc.so.6]
 0x000000000000001d (RUNPATH)            Library runpath: [$ORIGIN/]
 0x000000000000000c (INIT)               0x401000
 0x000000000000000d (FINI)               0x401244
 0x0000000000000019 (INIT_ARRAY)         0x403db8
 0x000000000000001b (INIT_ARRAYSZ)       16 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x403dc8
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x400308
 0x0000000000000005 (STRTAB)             0x400408
 0x0000000000000006 (SYMTAB)             0x400330
 0x000000000000000a (STRSZ)              269 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
➜  hello 
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值