c++ dlopen demo

01 C++方式使用dlopen

demo.cc

#include "shape.h"
#include 
#include 
#include 

// 编译
//g++ parallelogram.cc -fPIC -shared -o libparallelogram.so
//g++ demo.cc -ldl
//./a.out
// Parallelogram: Area: 1.73205 Perim: 6
// dlopen这个函数实际上如果不指定目录名./libparallelogram.so 这样子的话,会去本地的动态库目录内寻找。这时候就需要设置 LD_LIBRARY_PATH 环境变量。
// 此处带virtual关键字的函数,都是接口(interface) ,方便在装载不同动态库的时候,可实现同一接口但根据动态库不同来返回不同的信息内容(多态化)
// 在msys2 下 dlfcn.h: No such file or directory
// pacman -S mingw-w64-x86_64-dlfcn

int main()
{
	void *handle = dlopen("./libparallelogram.so", RTLD_LAZY);
	if (!handle)
	{
		std::cout << "Cannot open library" << std::endl;
		return 1;
	}

	create_t *create = (create_t *)dlsym(handle, "create");
	destroy_t *destroy = (destroy_t *)dlsym(handle, "destroy");
	if (!create || !destroy)
	{
		std::cout << "Cannot find symbols" << std::endl;
		return 1;
	}

	Shape *p = create();
    p->setShape(1,2,M_PI/3);
	p->print();
	destroy(p);
	dlclose(handle);
	
	return 0;
}

shape.h

#ifndef SHAPE_H
#define SHAPE_H

#include 

class Shape
{
public:
    Shape() {}
    virtual double getArea() const = 0;
    virtual double getPerim() const = 0;
    virtual void print() = 0;
    virtual void setShape(double edge1, double edge2, double angle) = 0;
    virtual ~Shape() {}
    static int count;
};

// the types of the class factories
typedef Shape *create_t();
typedef void destroy_t(Shape *);

void Shape::print()
{
    std::cout << "Area: " << getArea()
              << " Perim: " << getPerim() << std::endl;
}

#endif

parallelogram.cc

#ifndef PARALLELOGRAM_CC
#define PARALLELOGRAM_CC

#include "shape.h"
#include 

class Parallelogram : public Shape
{
protected:
    double edge1;
    double edge2;
    double angle;

public:
    Parallelogram(double edge1 = 0, double edge2 = 0, double angle = 0);
    
    virtual void setShape(double edge1, double edge2, double angle);
    virtual double getPerim() const;
    virtual double getArea() const;
    virtual void print();
};

Parallelogram::Parallelogram(double edge1, double edge2, double angle)
{
    this->edge1 = edge1;
    this->edge2 = edge2;
    this->angle = angle;
}
void Parallelogram::setShape(double edge1, double edge2, double angle)
{
    this->edge1 = edge1;
    this->edge2 = edge2;
    this->angle = angle;
}
double Parallelogram::getArea() const
{
    return edge1 * edge2 * sin(angle);
}

double Parallelogram::getPerim() const
{
    return 2 * (edge1 + edge2);
}

void Parallelogram::print()
{
    std::cout << "Parallelogram: ";
    Shape::print();
}

// the class factories
extern "C" Shape *create()
{
    return new Parallelogram;
}
extern "C" void destroy(Shape *p)
{
    delete p;
}
#endif // PARALLELOGRAM_CC

02 dlopen参数说明

void * dlopen(const char *pathname, int mode);
返回一个void *类型的handle,否则返回NULL。
pathname就是所要打开的动态库,如果这个库声明链接了其它库,即对其它库有依赖关系,那么所有相关有依赖关系的库都会被打开,这些打开的库称之为组(group)。

mode是打开方式,其值有多个,不同操作系统上实现的功能有所不同,
在linux下,按功能可分为三类:
1、解析方式
RTLD_LAZY:在 dlopen 返回前,对于动态库中的未定义的符号不执行解析(只对函数引用有效,对于变量引用总是立即解析)。
RTLD_NOW: 需要在 dlopen 返回前,解析出所有未定义符号,如果解析不出来,在dlopen会返回NULL,错误为:: undefined symbol: xxxx.......

2、作用范围 (可与解析方式通过“|”组合使用)
RTLD_GLOBAL:动态库中定义的符号可被其后打开的其它库重定位。
RTLD_LOCAL: 与RTLD_GLOBAL作用相反,动态库中定义的符号不能被其后打开的其它库重定位。如果没有指明是RTLD_GLOBAL还是RTLD_LOCAL,则缺省为RTLD_LOCAL

3、作用方式
RTLD_NODELETE: 在dlclose()期间不卸载库,并且在以后使用dlopen()重新加载库时不初始化库中的静态变量。这个flag不是POSIX-2001标准。
RTLD_NOLOAD: 不加载库。可用于测试库是否已加载(dlopen()返回NULL说明未加载,否则说明已加载),也可用于改变已加载库的flag,如:先前加载库的 flag为RTLD_LOCAL,用dlopen(RTLD_NOLOAD|RTLD_GLOBAL)后flag将变成RTLD_GLOBAL。这个flag不是POSIX-2001标准。
RTLD_DEEPBIND:在搜索全局符号前先搜索库内的符号,避免同名符号的冲突。这个flag不是POSIX-2001标准。

03 关于dlclose

dlopen 后,必须dlclose才会被卸载,在有些比支持加载检测(RTLD_NOLOAD )的版本中,要注意dlopen于dlclose的匹配。

04 Linux查看 可执行文件 依赖的 动态库的几个方法

lddobjdumppmappldd

1. 利用ldd查看可执行程序(动态库)的依赖库
使用 ldd -r XXX 查询动态库的依赖。关于undefined symbol使用 C++filt 查看
ldd libxxxx.so 或者 ldd binaryfileldd /usr/bin/bash)

2. 利用pldd获取进程的内存映射信息,进程的依赖共享库
pldd $(ps -ef | grep testdemo | grep -v grep | awk '{print $2}')

3. 利用objdump工具查询未知的可执行程序的依赖库.

#objdump -p /to/path/processname |grep NEEDED
objdump -p /usr/local/php/bin/php |grep NEEDED

4. 利用pmap查看正在运行时的进程的依赖库
pmap `pidof processname` |head或者 pmap pid |head

你可能感兴趣的:(c++,linux,c++)