赞
踩
demo.cc
#include "shape.h" #include <iostream> #include <dlfcn.h> #include <cmath> // 编译 //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 <iostream> 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 <cmath> 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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。