首页 > 其他分享 >dlopen参数flag的使用

dlopen参数flag的使用

时间:2023-05-01 20:33:20浏览次数:37  
标签:void flag so dlopen 参数 include libA RTLD

参考:https://blog.csdn.net/Bluenapa/article/details/119205993

使用dlopen接口动态加载共享库 ,函数原型如下

    void * dlopen( const char * pathname, int mode)

其第一个参数是包含so名称的路径,可以是相对路径;第二个参数mode是选项配置,可以结合实际场景需求配置,接下来认识下具体功能。

1、RTLD_NOW和RTLD_LAZY

  mode必须包含上述其中一个,表示解析方式,RTLD_NOW是调用dlopen后就解析所有函数符号,RTLD_LAZY是延时加载函数符号,使用的时候才解析,这样即使有一些未定义的函数符号,也能通过dlopen加载动态库。如下:main调用libA.so, 但是libA.so里面的函数里有未实现的函数,看看两个选项有啥区别。

  main.cpp

#include <unistd.h>
#include <dlfcn.h>
#include <stdio.h>
int main()
{
    // RTLD_NOW RTLD_LAZY
    void* handle = dlopen("./libA.so",RTLD_NOW);
    if (!handle)
       {
            printf("dlopen libA.so failed,err:%s\n",dlerror());
            return -1;
       }
    void (*func)(void)  = (void (*)(void))dlsym(handle,"funcA");
    if (!func)
       {
            printf("dlsym funcA failed, err: %s\n",dlerror());
            return -1;
       }
    func();
    return 0;
}

 A.cpp

#include <unistd.h>
#include <dlfcn.h>
#include <stdio.h>
extern "C" void funcB();
extern "C" void funcA()
{
funcB();
printf("this is funcA\n");
}

 编译命令:

g++ -fpic --shared A.cpp -o libA.so -ldl
g++ main.cpp -o main -ldl

  执行./main ,会在dlopen时就报错:  dlopen libA.so failed,err:./libA.so: undefined symbol: funcB

  如果将dlopen参赛mode改成RTLD_LAZY,就会发现调用dlopen和调用dlsym时都未报错,执行funcA时才报错:./main: symbol lookup error: ./libA.so: undefined symbol: funcB, 如果你不使用funcA,就不会出错

2、RTLD_LOCAL和RTLD_GLOBAL

  表示加载的函数符号的作用范围,RTLD_LOCAL与RTLD_GLOBAL作用相反,RTLD_GLOBAL 动态库中符号表全局打开,因此符号可被其后打开的其它库重定位;RTLD_LOCAL  动态库中符号表非全局打开,定义的符号不能被其后打开的其它库重定位。

  不填此选项,默认是RTLD_LOCAL

  如下:main加载libA.so,main加载libB.so并调用其函数funcB,而funcB调用A中funcA。(如果是mainmain加载libA.so,并调用funcA, libA.so动态加载libB.so, 并调用funcB,效果也是一样)

main.cpp

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

int main()
{
    // RTLD_NOW RTLD_LAZY
    // RTLD_LOCAL和RTLD_GLOBAL
    void* handle = dlopen("./libA.so",RTLD_NOW|RTLD_LOCAL);
    if (!handle)
       {
            printf("dlopen libA.so failed,err:%s\n",dlerror());
            return -1;
       }
    void* handleB = dlopen("./libB.so",RTLD_NOW);
    if (!handleB)
       {
            printf("dlopen libB.so failed,err:%s\n",dlerror());
            return -1;
       }
    void (*func)(void)  = (void (*)(void))dlsym(handleB,"funcB");
    if (!func)
       {
            printf("dlsym funcB failed, err: %s\n",dlerror());
            return -1;
       }
    func();
    return 0;
}

A.cpp

#include <unistd.h>
#include <dlfcn.h>
#include <stdio.h>
extern "C" void funcC();
extern "C" void funcA()
{
    printf("this is funcA\n");
}

B.cpp

#include <unistd.h>
#include <dlfcn.h>
#include <stdio.h>
extern "C" void funcA();
extern "C" void funcB()
{
    printf("this is funcB\n");
    funcA();
}

编译命令:

g++ -fpic --shared A.cpp -o libA.so -ldl
g++ -fpic --shared B.cpp -o libB.so -ldl
g++ main.cpp -o main -ldl

执行./main.cpp, 会报错:dlopen libB.so failed,err:./libB.so: undefined symbol: funcA, 将dlopen libA.so的参数改成RTLD_GLOBAL,funcB就可以找到funcA符号,程序执行就没问题了。

3、RTLD_NODELETE、RTLD_NOLOA、DRTLD_DEEPBIND

RTLD_NODELETE表示在dlclose()期间不卸载库,并且在以后使用dlopen()重新加载库时不初始化库中的静态变量

RTLD_NOLOAD用于验证动态库是否已加载,dlopen()返回NULL表示未加载,否则已加载;也可用于改变已加载库的flag,如:先前加载库的flag为RTLD_LOCAL,用dlopen(RTLD_NOLOAD|RTLD_GLOBAL)后flag将变成RTLD_GLOBAL

RTLD_DEEPBIND在规避同名符号冲突是很有用的,如果定义了此标志,在搜索全局符号时会优先搜索库内的符号,如下:main调用A里的funcA, funcA调用B里面的funcB函数,funcB调用funcC函数, libA.so和libB.so里面都有funcC函数

mian.cpp

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

int main()
{
    // RTLD_NOW RTLD_LAZY
    // RTLD_LOCAL和RTLD_GLOBAL
    void* handle = dlopen("./libA.so",RTLD_NOW|RTLD_GLOBAL);
    if (!handle)
       {
            printf("dlopen libA.so failed,err:%s\n",dlerror());
            return -1;
       }
    void (*func)(void)  = (void (*)(void))dlsym(handle,"funcA");
    if (!func)
       {
            printf("dlsym funcA failed, err: %s\n",dlerror());
            return -1;
       }
    func();
    return 0;
}

A.cpp

#include <unistd.h>
#include <dlfcn.h>
#include <stdio.h>
extern "C" void funcC()
{
    printf("this is libA funcC\n");
}
extern "C" void funcA()
{
    printf("this is funcA\n");
    // RTLD_NOW RTLD_LAZY
    // RTLD_LOCAL和RTLD_GLOBAL
    //  RTLD_DEEPBIND
    void* handle = dlopen("./libB.so",RTLD_NOW|RTLD_GLOBAL|RTLD_DEEPBIND);
    if (!handle)
       {
            printf("dlopen libB.so failed,err:%s\n",dlerror());
            return;
       }
    void (*func)(void)  = (void (*)(void))dlsym(handle,"funcB");
    if (!func)
       {
            printf("dlsym funcB failed, err: %s\n",dlerror());
            return;
       }
    func();
}

B.cpp

#include <unistd.h>
#include <dlfcn.h>
#include <stdio.h>
extern "C" void funcC()
{
    printf("this is libB funcC\n");
}
extern "C" void funcB()
{
    printf("this is funcB\n");
    funcC();
}

编译命令:

g++ -fpic --shared B.cpp -o libB.so -ldl
g++ -fpic --shared A.cpp -o libA.so -ldl
g++ main.cpp -o main -ldl

A.cpp里面的dlopen使用了RTLD_DEEPBIND选项,输出打印是this is libB funcC, 如果去掉RTLD_DEEPBIND选项,输出打印是 this is libA funcC

 

  

 

     

标签:void,flag,so,dlopen,参数,include,libA,RTLD
From: https://www.cnblogs.com/ho966/p/17366207.html

相关文章

  • upstream指令参数
    max_conns限制每台server的连接数,用于保护避免过载起限流作用测试参考配置如下:#worker进程设置1个,便于测试观察成功的连接数worker_process1;upstreamtomcats{server192.168.206.129:8080max_conns=2;server192.168.206.130:8080max_conns=2;......
  • C# 调用 C dll char* callback 设置回调函数不定参数
    1:C#调用返回字符串C++nativedll函数的注意事项:a:C++DLL的返回值,安全的做法是分配一个全局char数组,把要返回的char*复制到这个char数组中, charbuff[255];constchar*__stdcallReturnString(){strcpy(buff,"xxxxxxxxxxxxxxx");returnbuff;}......
  • 不一样的flag
    查壳32位,拖进IDA,老方法,找到flag,进入伪代码int__cdecl__noreturnmain(intargc,constchar**argv,constchar**envp){charv3[29];//[esp+17h][ebp-35h]BYREFintv4;//[esp+34h][ebp-18h]intv5;//[esp+38h][ebp-14h]BYREFinti;//[esp+3Ch][......
  • 推翻OpenAI结论,DeepMind重新定义预训练的参数和规模关系!
    文|王思若前言从20年开始,“最大语言模型”的桂冠被各大研究机构和科技公司竞相追逐,堆砌参数,猛上算力,开启了“大炼丹”时代,模型参数量仿佛越大越好,甚至GPT-4模型参数量将超过100万亿的传闻甚嚣尘上。当把视角落在今年下半年,大模型的“军备竞赛”似乎戛然而止,22年4月,Google发布了5400......
  • Django框架——Q查询进阶、ORM查询优化、事务操作、字段类型、字段参数、Ajax、Conten
    Q查询进阶fromdjango.db.modelsimportQq_obj=Q()#1.产生q对象q_obj.connector='or'#默认多个条件的连接是and可以修改为orq_obj.children.append(('pk',1))#2.添加查询条件q_obj.children.append(('price__gt',2000))#支持添加多个res=models.Book.o......
  • sys.argv命令行参数使用
    用户命令行配置参数:代码如下:importsysiflen(sys.argv)<2:print('tip:')print('1.select')print('2.select')print('3.select')else:foriinsys.argv[1:]:print(i)......
  • 定义函数时不要使用可变类型作为参数的默认值
    《流畅的Python》第8章8.4.1小节 可变默认值导致的这个问题说明了为什么通常使用None作为接收可变值的参数的默认值。类名.__init__.__defaults__:查看类中形式参数的默认值函数名.__defaults__属性:查看形式参数的默认值#形式参数L是可变类型时隐藏的问题defadd_end(L=[......
  • C#--ref和out参数
    1,普通参数1.1,带普通参数的方法staticvoidfun(inta)//普通的函数参数是将a的值传入的,单独创建一个临时空间存a的值,函数结束了a的临时内存空间就不存在了{a=a+3;Console.WriteLine($"普通参数,a的值为{a}");}1.2,调......
  • c宏实现批量设置参数
    点击查看代码#defineFOO(name)(uint64_t)name,#defineEMPTY()#defineDEFER(id)idEMPTY()#defineFOR_EACH(macro,x,...)CAT(FOR_EACH_,ff(__VA_ARGS__))(macro,x,##__VA_ARGS__)#defineFOR_EACH_0(macro,x,...)macro(x)DEFER(FOR_EACH_I)()(macro,_......
  • go语言 数组和切片、可变长参数、maps、字符串、指针、结构体、方法、接口
    数组和切片数组#1定义,初始化,使用#2数组是值类型数字,字符串,布尔,数组,都是值类型,真正直接存数据切片,map,指针引用类型,是个地址,指向了具体的值#3数组长度#4循环打印数组#5多纬数组#6数组定义并赋初值,把第99赋值为1,其他都是0#数组的长度也......