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
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
标准。
dlopen 后,必须dlclose才会被卸载,在有些比支持加载检测(RTLD_NOLOAD
)的版本中,要注意dlopen于dlclose的匹配。
ldd
、objdump
、pmap
、pldd
1. 利用ldd查看可执行程序(动态库)的依赖库
使用 ldd -r XXX 查询动态库的依赖。关于undefined symbol使用 C++filt 查看
ldd libxxxx.so
或者 ldd binaryfile
(ldd /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