把共享库(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(intn)

{

    returnn;

}

test1.c

inttest1(intn)

{

    returnn;

}

main.c

externinttest(intn);

externinttest1(intn);

#include <stdio.h>

 

intmain(intargc, 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]

 

从以上测试结果可以看出,这种方法是可行的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/435331.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

aop实现原理_SpringAOP原理分析

目录Spring核心知识SpringAOP原理AOP编程技术什么是AOP编程AOP底层实现原理AOP编程使用Spring核心知识Spring是一个开源框架&#xff0c;Spring是于2003年兴起的一个轻量级的Java开发框架&#xff0c;由Rod Johnson在其著作Expert One-On-One J2EE Development and Design中阐述…

欧盟无条件批准甲骨文收购Sun

北京时间1月21日消息&#xff0c;据国外媒体报道&#xff0c;甲骨文以70亿美元的价格收购Sun的交易今天获得了欧盟无条件批准。 这笔交易将改变科技产业的格局&#xff0c;这意味着全球第二大商用软件提供商甲骨文进入了硬件产业。在规模达170亿美元的高端计算机服务器市场&…

如何高效的访问内存

影响内存访问速度的因素主要有&#xff1a; 1.内存带宽&#xff1a;每秒读写内存的数据量&#xff0c;由硬件配置决定。 2.CACHE高速缓冲&#xff1a;CPU与内存之间的缓冲器&#xff0c;当命中率比较高时能大大提供内存平均访问速度。 3.TLB转换旁视缓冲&#xff1a;系统虚拟地…

初学者怎样看懂python代码_入门编程(初学者怎样看懂代码)

你既然喜欢编程&#xff0c;就应该认认真真的学习一门语言&#xff0c;学习微软的就先从vb开始&#xff0c;vb是比较好的入门语言&#xff0c;可视化的&#xff0c;比较简单&#xff0c;是非常好的入门语言。书籍最少应该准备两. 先认认真真的学习一门语言&#xff0c;学习微软…

MAVEN安装和配置

maven官网下载 https://maven.apache.org/download.cgi

MIPS架构的医院智能导诊系统设计

摘要&#xff1a;通过研究基于MIPS架构的SMP8654芯片的硬件架构&#xff0c;并且利用芯片内部的图形加速引擎GFX的方式实现了具有高清视频显示和图片文字处理功能的播放器。系统以嵌入式Linux和MiniGUI为平台设计了智能导诊系统&#xff0c;提高了医院的导诊就医的服务效率。智…

C、CPP const 详解

1.const修饰变量一般有两种写法&#xff1a; constTYPE value;TYPE constvalue;这两种写法在本质上是一样的。它的含义是&#xff1a;const修饰的类型为TYPE的变量value是不可变的。对于一个非指针的类型TYPE&#xff0c;无论怎么写&#xff0c;都是一个含义&#xff0c;即valu…

arcgis在线地图插件安装

软件下载链接 https://download.csdn.net/download/qq_39397927/15761863

hadoop namenode启动不了_集群版hadoop安装,写给大忙人看的

导语 如果之前的单机版hadoop环境安装满足不了你&#xff0c;集群版hadoop一定合你胃口&#xff0c;轻松入手。目录 集群规划前置条件配置免密登录 3.1 生成密匙 3.2 免密登录 3.3 验证免密登录集群搭建 4.1 下载并解压 4.2 配置环境变量 4.4 修改配置 4.4 分发程序 4.5 初始化…

patch文件制作

一、为单个文件打补丁1、首先我用的ubuntu12 os&#xff0c;cat >>test0<<eof但是这命令执行得是root身份more命令功能&#xff1a;让画面在显示满一页时暂停&#xff0c;此时可按空格健继续显示下一个画面&#xff0c;或按Q键停止显示。more test0:查看test0内容2…

[转]百万级访问网站前期的技术准备

作者&#xff1a;一路凯歌来源&#xff1a;http://zhiyi.us/ 开了自己域名的博客&#xff0c;第一篇就得来个重磅一点的才对得起这4美金的域名。作为一个技术从业者十年&#xff0c;逛了十年发现有些知识东一榔头西一棒槌的得满世界 看个遍才整理出个头绪&#xff0c;那咱就系统…

java string逆序_java经典入门算法题,java初学者必备

java经典入门算法题开头求关注警告喜欢这样文章的可以关注我&#xff0c;我会持续更新&#xff0c;你们的关注是我更新的动力&#xff01;需要更多java学习资料的也可以私信我&#xff01;祝关注我的人都&#xff1a;身体健康&#xff0c;财源广进&#xff0c;福如东海,寿比南山…

u-boot的patch文件制作

首先明白为什么要制作patch文件&#xff0c;因为u-boot的移植过程需要根据实际需要修改通用u-boot&#xff0c;如果每次手工修改的话&#xff0c;太麻烦&#xff0c;所以用了patch文件一步到位&#xff0c;这点类似于makefile的作用&#xff0c;哈哈1.了解 diff 和 patch。diff…

Powershell 最大值堆栈实现

Powershell 最大值堆栈实现 下面代码基于一个算法题目来实现一个用线性时间得到堆栈最大值的代码。 cls$maxStackConut 5$stackTopIndex -1$stack New-Object int[] ($maxStackConut) $link2NextMaxItem New-Object int[] ($maxStackConut)$maxStackItemIndex-1 function Pus…

python主线程执行_在Django vi中的主线程中执行Python函数

我创建了Django视图“graph”&#xff0c;目的是显示从matplotlib.pyplot模块。我编写了我的函数plot\u bubbles&#xff08;返回amatplotlib.figure.figure对象&#xff09;在脚本数据中_分析.py导入到视图.py脚本。在 Tkinter只能在主线程上运行&#xff0c;我的网页在我第一…

postgis创建空间数据库(pgadmin4)

打开软件 看我之前的安装步骤的用户密码为postgres 点击save 查看是否具有空间数据 1.查看是否存在空间数据表 2.查看是否具有空间函数

Outlook最小到系统托盘

Outlook最小到系统托盘 默认状态下outlook最小化以后在任务栏上还占一个位置&#xff0c;又不常用&#xff0c;关了又不能实时接收到邮件&#xff0c;可以通过以下方法隐藏到系统托盘&#xff0c;解决方法如下&#xff1a; 如果你用得是Office2007: 1 打开注册表&#xff1a;开…

嵌入式linux的学习笔记-共享内存(六)

共享内存共享内存是可以被多个进程共享访问的一部分物理内存,如果多个进程都把一个内存区映射到自身的虚拟地址空间,则这些进程就可以直接访问该共享的内存区域,从而通过共享内存的方式实现多进程间的通讯,共享内存是进程间数据通讯的最快方法.共享内存的实现分为两步:1,创建共…

SQL Server 2012 安装

SQL Server 2012 安装 安装包在这里&#xff1a;https://pan.baidu.com/s/1_sgxN8P-pzj7uZeAR0VlKQ 提取码&#xff1a;mnvj 文件比较大&#xff0c;慢慢下载吧 下载好后是这样的&#xff1a; 双击打开&#xff0c;点击 setup.exe 安装&#xff1a; 选择“安装”&#xff0…