linux下动态库

今天无意间发现在linux下share object(dynamic library)中的函数竟然可以不通过回调的方式直接访问主程序中的函数,瞬间颠覆以前对于动态库的观念.

1、如下代码所示,ibhi.so中有一个函数hello, 主程序main中有一个函数hi_out, 那么在main中调用libhi.so中的hello时,hello会自动找到main程序中的hi_output函数地址, 然后进行调用.

=================hi.c 编译为 libhi.so===========

extern void hi_out();

void hello(){

hi_out();

...;

}

=================main.c 编译为 elf_lnk=============

#include

void hi_out(){

printf("hi out.\n");

}

extern void hello(); //语句1

int main() {

hello(); //语句2

return 0;

}

利用命令gcc -shared -fPIC -o libhi.so hi.c     把hi.c源文件编译成libhi.so

利用命令gcc main.c -L. -lhi -Wl,-rpath,. -o elf_lnk 把main.c和libhi.so一起编译链接,生成可执行文件(elf_lnk)指向动态库libhi.so

在感叹linux下动态库强大的同时, 对于其实现机制也产生了好奇. 经过一番努力终于在《程序员的自我修养》中第7.6.2章找到答案.

“动态链接器在完成基本自举后, 动态链接器将可执行文件和链接器本身的符号表都合并到一个符号表中, 我们可以称它为全局符号表(Global Symbol Table)…..当一个新的share object被装载进来的时侯, 它的符号表会被合并到全局符号表中”, 因此其实libhi.so在调用hello函数时实际上是从全局符号表中找到hi_out函数的地址并进行调用, 本质上libhi.so并不知道这个hi_out是属于另一个share object还是属于main程序中.

2、但当我使用dlopen系列函数动态加载libhi.so时, 却总是加载失败提示找不到hi_out函数. 理论上静态加载与动态加载上的行为应该是一样的, 只不过静态加载时dlopen将会被隐式调用而已.

代码如下,把上面的语句1和语句2删除,增加了一些dlopen的代码。

利用命令gcc main.c -ldl -o elf_dl 编译成可执行文件elf_dl,运行时会报错 语句3的打印

load dlopen(/root/libhi.so): /root/libhi.so: undefined symbol: hi_out

=================hi.c 编译为 libhi.so===========

extern void hi_out();

void hello(){

hi_out();

...;

}

=================main.c 编译为 elf_dl=============

#include

#include //dlopen的头文件

void hi_out(){

printf("hi out.\n");

}

int main() {

const char* pstr = "/root/libhi.so";

void *library = dlopen(pstr, RTLD_NOW); //如果用RTLD_LAZY,则会在语句4报错

if (!library ) {

printf("load dlopen(%s): %s\n", pstr, dlerror() ); //语句3,RTLD_NOW模式在这报错

return -1;

}

void (*pfun) ();

pfun = (void(*)()) dlsym(library, "hello");

if (pfun){

pfun(); //语句4

}

return 0;

}

在 ld手册 找到了答案, ld在生成可执行文件时, 默认只导出被其他动态库使用的符号. 因为是使用dlopen去动态加载libhi.so, 那么链接时ld并不知道可执行文件中的hi_out会被外部引用, 也就不会导出hi_out到动态符号表去. 当dlopen打开libhi.so时, 动态链接器在全局符号表中找不到hi_out符号, 理所当然就报错了.

要解决这个问题只要给链接器加上参数-E将主程序中所有全局符号放到动态符号表中即可, 由于生成可执行文件一般都是gcc直接生成, 因此可以使用gcc -Wl,-E来将-E参数传给ld来完成创建一个可以被动态链接的可执行文件.

编译主程序: gcc main.c -Wl,-E -ldl -o elf_dl  , 编译成可执行文件elf_dl,运行ok。

或者把-Wl,-E换成 -rdynamic,可以实现一眼的效果,用来通知链接器,把全部符号加入到动态符号表中(目的是dlopen的so库可以通过使用这些符号)

3、后记

可以用nm,或者ldd来查看libhi.so里面的未定义符号

[root]# nm libhi.so | grep hi_out

U hi_out

[root]# ldd -r libhi.so

....省略

undefined symbol: hi_out (./libhi.so)

so库调用java函数_linux下so动态库调用主程序函数相关推荐

  1. linux查看动态库导出的符号,Linux下控制动态库导出

    在Linux中动态库的确给程序带来了良好的扩充性,并减少了内存的使用量,但这是有代价的.例如: #include Int main(int argc, char *argv[]) { Printf(& ...

  2. linux 下的动态库制作 以及在python 中如何调用 c 函数库

    linux 下的动态库制作 以及在python 中如何调用 c 函数库 动态库: 动态库又称动态链接库英文为DLL,是Dynamic Link Library 的缩写形式,DLL是一个包含可由多个程序 ...

  3. 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 二 | 准备参数 | 远程调用 mmap 函数 )

    文章目录 一.准备 mmap 函数的参数 二.mmap 函数远程调用 一.准备 mmap 函数的参数 上一篇博客 [Android 逆向]Android 进程注入工具开发 ( 注入代码分析 | 远程调 ...

  4. 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 三 | 等待远程函数执行完毕 | 寄存器获取返回值 )

    文章目录 前言 一.等待远程进程 mmap 函数执行完毕 二.从寄存器中获取进程返回值 三.博客资源 前言 前置博客 : [Android 逆向]Android 进程注入工具开发 ( 注入代码分析 | ...

  5. Unix下设计动态库的方法《精通Unix下C语言编程与项目实践》(一)

    精通Unix下C语言编程与项目实践 之动态库的生成 作者:朱云翔,胡平 3.3 动态库的生成 动态库的生成可分为三个步骤,设计库源码.编译位置无关码(PIC)型.o文件和链接动态库.链接动态库的命令包 ...

  6. 【Android 安装包优化】使用 lib7zr.so 动态库处理压缩文件 ( 测试 lib7zr.so 动态库调用 )

    文章目录 一.拷贝 p7zip 源码中的头文件到 Android Studio 项目中 二.完整代码示例 1.Java 层代码 2.JNI 层代码 3.日志头文件 4.执行结果 四.参考资料 前置博客 ...

  7. Linux下的动态库和静态库

    什么是库? 在 Linux 开发时,我们经常会看到一些形如 xxx.so 的名称出现,其中 so 是 Shared Object 的缩写,即可以共享的目标文件,也就是我们所称为的动态链接库,和在 Wi ...

  8. Linux 下的动态库、静态库与环境变量

    最近这几天在处理集群软件的过程中,遇到各种各样的库和环境变量的问题,被虐的不清!趁此机会,整理了一下 Linux 下静态库.动态库(共享库)和环境变量的一些知识,与大家共享一下. 库的种类 Linux ...

  9. 【Android 逆向】函数拦截实例 ( 函数拦截流程 | ① 定位动态库及函数位置 )

    文章目录 一.函数拦截流程 二.定位动态库及函数位置 一.函数拦截流程 函数拦截流程 : 定位动态库及函数位置 : 获取该动态库在内存中的位置 , 以便于 查找函数位置 ; 插桩 : 在函数的入口处插 ...

最新文章

  1. linux 存储映射lun 给_在Linux中针对物理磁盘和LUN映射Oracle ASM磁盘
  2. Halcon基础知识:常规数据、对象数据、对象元组
  3. Spring 中经典的 9 种设计模式,打死也要记住啊!
  4. 太强了!顶尖高校学霸“神仙笔记”刷屏,这10类专业绝了
  5. BugkuCTF-MISC题闪的好快
  6. 超好看的动漫二次元引导页源码
  7. [深度学习-原理]GAN(生成对抗网络)的简单介绍
  8. CCF NOI1039 2的n次方
  9. Unsafe in Java
  10. nodeJS丶Buff使用及相关API
  11. c++ explicit关键字解读
  12. php环境下cache失效,cache缓存失效高并发读数据库的问题
  13. linux下的ps4手柄驱动,DS4 To XInput Wrapper
  14. plc无线连接服务器,plc连接云服务器
  15. 【SDK】Android海康网络SDK实现人脸和车牌等报警图片抓拍功能
  16. 职称论文发表教育期刊《中小学教育》杂志简介及投稿须知
  17. HTML实现文件上传和HTML实现打开文件目录
  18. 安全芯片的功能是什么
  19. 中兴c600olt数据配置_中兴OLT配置脚本
  20. 信道容量、码率、带宽、频谱利用率

热门文章

  1. Oracle 20c 新特性:SQL 宏支持(SQL Macro)Scalar 和 Table 模式
  2. 这样做,免费从Oracle同步数据
  3. 关于HTTPS认证,这里解决你所有疑惑
  4. 5G to B核心网建设白皮书发布:2025年运营商toB市场高达6020亿美元
  5. 深入比特币原理(一)——比特币白皮书总结与点评
  6. java 动态网页_JavaWeb01-动态网页
  7. ora-28500 ora-02063 mysql_oracle dblink mysql 报错ORA-28500
  8. 根据企业财务进行风险分析——基于pytorch
  9. Python 绘制散点图
  10. 商丘高中计算机考试成绩查询系统,河南省中招考生服务平台2019商丘中考成绩查询系统入口...