把共享库(SO)加载到指定的内存地址
一位朋友最近遇到一个棘手的问题,希望把共享库(SO)加载到指定的内存地址,目的可能是想通过prelink来加快应用程序的起动速度。他问我有没有什么方法。我知道Windows下是可以的,比如在VC6里设置/base的值就行了,所以相信在Linux下也是可行的。
VC有编译选项可以设置,猜想gcc也应该有吧。gcc本身只是一个外壳,链接工作是由于ld完成的,当然是应该去阅读ld命令行选项文档。很快发现ld有个—image-base选项,可以设置动态库的加载地址。
通过Xlinker把这个参数传递给ld,但是ld不能识别这个选项:
gcc -g -shared test.c -Xlinker --image-base -Xlinker 0x00c00000 -o libtest.so
/usr/bin/ld: unrecognized option '--image-base'
/usr/bin/ld: use the --help option for usage information
collect2: ld returned 1 exit statu
s
再仔细看手册,原来这个选项只适用于PE文件,PE文件是Windows下专用的,在linux下自然用不了,看来得另想办法。
我知道ld script可以控制ld的行为,于是研究ld script的写法,按照手册里的说明,写了一个简单的ld script:
SECTIONS { . = 0x00c00000; .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } } |
按下列方式编译:
gcc -shared -g -Xlinker --script -Xlinker ld.s test.c -o libtest.so
gcc -g main.c -L./ -ltest -o test.exe
用ldd查看,加载地址正确。
[root@localhost lds]# ldd test.exe
linux-gate.so.1 => (0x00aff000)
libtest.so => ./libtest.so (0x00c00000)
libc.so.6 => /lib/libc.so.6 (0x007fa000)
/lib/ld-linux.so.2 (0x007dd000)
但运行时会crash:
[root@localhost lds]# ./test.exe
Segmentation fault
调试运行可以发现:
(gdb) r
Starting program: /work/test/lds/test.exe
Reading symbols from shared object read from target memory...done.
Loaded system supplied DSO at 0x452000
Program received signal SIGSEGV, Segmentation fault.
0x007e7a10 in _dl_relocate_object () from /lib/ld-linux.so.2
(gdb) bt
#0 0x007e7a10 in _dl_relocate_object () from /lib/ld-linux.so.2
#1 0x007e0833 in dl_main () from /lib/ld-linux.so.2
#2 0x007f056b in _dl_sysdep_start () from /lib/ld-linux.so.2
#3 0x007df48f in _dl_start () from /lib/ld-linux.so.2
#4 0x007dd847 in _start () from /lib/ld-linux.so.2
猜想可能是ld.s写得不全,导致一些信息不正确。于是用ld –verbose导出一个默认的ld script。不出所料,默认的ld script非常冗长,下面是开头一段:
/* Script for -z combreloc: combine and sort reloc sections */ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(_start) SEARCH_DIR("/usr/i386-redhat-linux/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); SECTIONS { /* Read-only sections, merged into text segment: */ PROVIDE (__executable_start = 0x08048000); . = 0x08048000 + SIZEOF_HEADERS; .interp : { *(.interp) } .hash : { *(.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } .gnu.version_d : { *(.gnu.version_d) } .gnu.version_r : { *(.gnu.version_r) } |
按照ld script的语法,我把它修改为(红色部分为新增行):
/* Script for -z combreloc: combine and sort reloc sections */ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(_start) SEARCH_DIR("/usr/i386-redhat-linux/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); SECTIONS { /* Read-only sections, merged into text segment: */ PROVIDE (__executable_start = 0x08048000); . = 0x08048000 + SIZEOF_HEADERS; . = 0x00c00000; .interp : { *(.interp) } .hash : { *(.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } .gnu.version_d : { *(.gnu.version_d) } .gnu.version_r : { *(.gnu.version_r) } |
用这个ld script再次测试,一切正常。又验证多个共享库的情况,也正常,下面是测试数据:
test.c
int test(int n) { return n; } |
test1.c
int test1(int n) { return n; } |
main.c
extern int test(int n); extern int test1(int n); #include <stdio.h> int main(int argc, char* argv[]) { printf("Hello: %d %d/n", test(100), test1(200)); getchar(); return 0; } |
Makefile
all: gcc -shared -g -Xlinker --script -Xlinker ld.s test.c -o libtest.so gcc -shared -g -Xlinker --script -Xlinker ld1.s test1.c -o libtest1.so gcc -g main.c -L./ -ltest -ltest1 -o test.exe clean: rm -f *.so *.exe |
libtest.so的加载地址为:0x00c00000
libtest1.so的加载地址为:0x00d00000
ldd显示结果:
linux-gate.so.1 => (0x00aa3000) libtest.so => ./libtest.so (0x00c00000) libtest1.so => ./libtest1.so (0x00d00000) libc.so.6 => /lib/libc.so.6 (0x007fa000) /lib/ld-linux.so.2 (0x007dd000) |
maps的内容为:
007dd000-007f6000 r-xp 00000000 03:01 521466 /lib/ld-2.4.so 007f6000-007f7000 r-xp 00018000 03:01 521466 /lib/ld-2.4.so 007f7000-007f8000 rwxp 00019000 03:01 521466 /lib/ld-2.4.so 007fa000-00926000 r-xp 00000000 03:01 523579 /lib/libc-2.4.so 00926000-00929000 r-xp 0012b000 03:01 523579 /lib/libc-2.4.so 00929000-0092a000 rwxp 0012e000 03:01 523579 /lib/libc-2.4.so 0092a000-0092d000 rwxp 0092a000 00:00 0 00c00000-00c01000 r-xp 00001000 03:03 16370 /work/test/ldsex/libtest.so 00c01000-00c02000 rwxp 00001000 03:03 16370 /work/test/ldsex/libtest.so 00cf1000-00cf2000 r-xp 00cf1000 00:00 0 [vdso] 00d00000-00d01000 r-xp 00001000 03:03 16373 /work/test/ldsex/libtest1.so 00d01000-00d02000 rwxp 00001000 03:03 16373 /work/test/ldsex/libtest1.so 08048000-08049000 r-xp 00000000 03:03 16374 /work/test/ldsex/test.exe 08049000-0804a000 rw-p 00000000 03:03 16374 /work/test/ldsex/test.exe b7fdf000-b7fe0000 rw-p b7fdf000 00:00 0 b7fed000-b7ff0000 rw-p b7fed000 00:00 0 bf8db000-bf8f0000 rw-p bf8db000 00:00 0 [stack] |
从以上测试结果可以看出,这种方法是可行的。
把共享库(SO)加载到指定的内存地址相关推荐
- linux动态库ldd加载顺序,ldd查看动态依赖库
ldd命令用于输出程序或者库文件所依赖的共享库列表. 语法 ldd (选项) (参数) 选项 --help:显示帮助信息 --version:打印指令版本号: -v:详细信息模式,打印所有相关信息: ...
- iphone静态库的加载和调试
一. iphone静态库的加载:使用静态库需要提供*.a库文件和*.h头文件. 1. 在xcode中Frameworks项上点击右键add->existing files选择*.a库文件 2. ...
- 第一百四十一节,JavaScript,封装库--DOM加载
JavaScript,封装库--DOM加载 DOM加载,跨浏览器封装DOM加载,当网页文档结构加载完毕后执行函数,不等待图片音频视频等文件加载完毕 /** dom_jia_zai()函数,DOM页面加 ...
- k n:linux kernel 从开机,到加载内核镜像到内存
原文地址: linux的内核运行原理是怎么样的呢?如何从开机,到加载内核镜像到内存? linux的内核运行原理是怎么样的呢?如何从开机,到加载内核镜像到内存? 最佳答案 本回答由提问者推荐 头像 匿名 ...
- System.DllNotFoundException: 无法加载 DLL“GdltaxIA.dll”: 内存位置访问无效。 (异常来自 HRESULT:0x800703E6)。 WIN7系统
System.DllNotFoundException: 无法加载 DLL"GdltaxIA.dll": 内存位置访问无效. (异常来自 HRESULT:0x800703E6). ...
- 记录--深度学习加载大数据集遭遇内存和磁盘io瓶颈的问题
1--问题描述 在最近的一个课题中,需要加载接近1T的数据集.由于内存的限制,无法一次加载整个数据集到内存中. 想到的一个解决方案是,将大数据集处理为单个样本,根据DataLoader随机产生的索引i ...
- Delphi FMX正确加载图片最大限度减少内存占用(之一TBitmapSurface)
Delphi FMX正确加载图片最大限度减少内存占用(之一TBitmapSurface) 国庆前,无意间发现App内存占用陡增,发现是几张4K图片(7680x4320像素)加载引发的(TImage.B ...
- Delphi FMX正确加载图片最大限度减少内存占用(之二TImageList)
Delphi FMX正确加载图片最大限度减少内存占用(之二TImageList) 继上篇<Delphi FMX正确加载图片最大限度减少内存占用(之一TBitmapSurface)>之后,我 ...
- 某些error page不加载_细说So动态库的加载流程
本文为看雪论坛优秀文章 看雪论坛作者ID:sossai dlopen之内存装载dlopen用来打开一个动态链接库,并将其装入内存.它的定义在Android源码中的路径为/bionic/linker/d ...
最新文章
- vb6调用python识别训练例子_在vb6中创建的“标准”dll在python中调用时会出现访问冲突...
- 【多标签文本分类】Initializing neural networks for hierarchical multi-label text classification
- Vue 单文件组件||Vue 单文件组件的基本用法||webpack 中配置 vue 组件的加载器|| 在 webpack 项目中使用 vue
- spring mvc DispatcherServlet详解之一--request通过HandlerMaping获取控制器Controller过程
- 第七章 DevOps工具链
- OCM备考 一、Server config 之手工创建数据库
- linux文件属性之用户和组基础知识
- 前端学习(2525):实现过滤功能
- spring心得6--自动装配知识点讲解及案例分析
- JavaScript 文件拖拽上传插件 dropzone.js 介绍
- Window_纪中_1326_单调队列
- LoadRunner10自带的WEBTOURS,无法显示Flights页面问题解决办法
- node.js学习文档_学习NodeJs从每天一个小知识点开始
- 【Linux】系统移植篇四--uboot移植
- 二次线性插值实现图像放大(计算机视觉)
- Ai 缺失字体解决方法
- Java面试集合(四)
- 虚拟机安装Windows7系统(亲测超详细)
- CANopen协议基础知识
- Excel,根据一列的子集进行筛选