计算机系统-从应用程序到底层实现 课件 第18讲 Link-4_第1页
计算机系统-从应用程序到底层实现 课件 第18讲 Link-4_第2页
计算机系统-从应用程序到底层实现 课件 第18讲 Link-4_第3页
计算机系统-从应用程序到底层实现 课件 第18讲 Link-4_第4页
计算机系统-从应用程序到底层实现 课件 第18讲 Link-4_第5页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

《计算机系统》链接plus篇《计算机系统》课程教学组2025年春季学期可执行文件vs.

进程的存储映射ELFheaderProgramheadertable(requiredforexecutables).textsection.datasection.bsssection.symtab.debugSectionheadertable(requiredforrelocatables)ExecutableObjectFileKernelvirtualmemoryMemory-mappedregionforsharedlibrariesRun-timeheap(createdbymalloc)Userstack(createdatruntime)Unused%esp

(stackpointer)Memoryoutside32-bitaddressspacebrk0x1000000000x080480000xf7e9ddc0Read/writesegment(.data,.bss)Read-onlysegment(.init,.text,.rodata)Loadedfromtheexecutablefile.rodatasection.line.initsection.strtab可执行文件的加载通过调用execve系统调用函数来调用加载器加载器(loader)根据可执行文件的程序(段)头表中的信息,将可执行文件的代码和数据从磁盘“拷贝”到存储器中(实际上不会真正拷贝,仅建立一种映像,此处可以回忆一下OS的内容,后续我们还会讲VM)加载后,将PC(EIP)设定指向Entrypoint

(即符号_start处),最终执行main函数,以启动程序执行。程序被启动如$./P调用fork()以构造的argv和envp为参数调用execve()execve()调用加载器进行可执行文件加载,并最终转去执行main__libc_init_first_initatexitmain_exit_start:ELF文件信息示例ELF文件信息示例int__libc_start_main(int(*main)(int,char**,char**),intargc,char**ubp_av,void(*init)(void),void(*fini)(void),void(*rtld_fini)(void),void(*stack_end));//初始化程序运行环境,并调用main()函数开始程序的执行。ELF文件信息示例库静态库共享库链接器本讲内容打包常用函数如何打包编程者经常使用的功能函数?Math,I/O,memorymanagement,stringmanipulation等不那么合适的待选方案:Option1:将所有函数写入一个源代码文件编程者需要将一个很大的目标文件链接到其程序空间和时间性能都低Option2:每一个函数形成一个单独的源文件编程者需将自己的程序显示地链接到相应的二进制文件更有效,但对于编程者是额外负担解决方法静态库静态库(.a

存档文件集)一组连接起来的可重定位目标文件集合,有一个头部用来描述每个成员目标文件的大小和位置增强了链接器,其可以通过在一个或多个存档中查找符号来解析外部引用若一个存档成员文件解析了引用,则可将其连接到可执行文件

创建静态库Translatoratoi.catoi.oTranslatorprintf.cprintf.olibc.aArchiver(ar)...Translatorrandom.crandom.o$arrcslibc.aatoi.oprintf.o…random.oC标准库存档文件(Archiver)允许增量升级更新

重编译的函数改变并替换存档中的原有.o文件通用库libc.a(theCstandardlibrary)8MBarchiveof1392objectfiles.I/O,memoryallocation,signalhandling,stringhandling,dataandtime,randomnumbers,integermathlibm.a(theCmathlibrary)1MBarchiveof401objectfiles.floatingpointmath(sin,cos,tan,log,exp,sqrt,…) $ar-t/usr/lib/libc.a|sort…fork.o…fprintf.ofpu_control.ofputc.ofreopen.ofscanf.ofseek.ofstab.o…$ar-t/usr/lib/libm.a|sort…e_acos.oe_acosf.oe_acosh.oe_acoshf.oe_acoshl.oe_acosl.oe_asin.oe_asinf.oe_asinl.o…链接中的静态库Translators(cpp,cc1,as)main2.cmain2.olibc.aLinker(ld)p2printf.oandanyothermodulescalledbyprintf.olibvector.aaddvec.oStaticlibrariesRelocatableobjectfilesFullylinkedexecutableobjectfilevector.hArchiver(ar)addvec.omultvec.o使用静态库解析外部引用的链接器算法:

E将被合并以组成可执行文件的所有目标文件集合,起初为Φ U当前所有未解析的引用符号的集合,起初为Φ D当前所有定义符号的集合,起初为Φ按照命令行顺序扫描.o

目标文件,加入E

,并将当前未解析引用的符号入列表U

,已解析符号入列表D;再扫描.a文件,将U中的符号与静态库中定义的符号依次匹配,匹配成功,则将符号从U移出,放入D;若在扫描结束时,未解析列表U中仍有条目存在,则报错

;否则合并和重定位E中目标文件,形成可执行文件。存在问题:此时,命令行中的顺序很重要!原则上应将库文件放在命令行的末尾

$gcc-static

main.c./libvector.a

$gcc–static./libvector.amain.c…….o:Infunction`main':…….o(.text+0x18):undefinedreferenceto`addvec'共享库静态库存在如下缺点:在存储中的可执行文件中有多个副本(每一个函数均需要静态库文件)在运行中的可执行文件中存在多个副本

即便是对系统库进行小bug的修复,也需要对使用到这个库的所有应用显示地重新链接

更好的解决方案:共享库包含代码和数据的目标文件,或者在加载时,或者在执行时,被动态加载和链接到应用中

也被称为:动态链接库,DLLs,.so文件使用共享库在内存中只有一个备份,被所有进程共享(调用),节省内存空间一个共享库目标文件被所有程序共享链接,节省硬盘空间共享库升级时,被自动加载到内存和程序动态链接,使用方便共享库可分模块、独立、用不同编程语言进行开发,效率高第三方开发的共享库可作为程序插件,使程序功能易于扩展加载时的动态链接Translators(cpp,cc1,as)main2.cmain2.olibc.solibvector.soLinker(ld)p2Dynamiclinker(ld-linux.so)Relocationandsymboltableinfolibc.solibvector.soCodeanddata部分链接的可执行目标文件

可重定位目标文件存储器中完全链接的可执行文件vector.hLoader(execve)$gcc-shared-olibvector.soaddvec.cmultvec.c-fPIC动态链接用到一个重要概念:位置无关代码(Position-IndependentCode,PIC)GCC选项-fPIC指示生成PIC代码共享库代码是一种PIC共享库代码的位置可以是不确定的即使共享库代码的长度发生变化,也不影响调用它的程序引入PIC的目的链接器无需修改代码即可将共享库加载到任意地址运行要实现动态链接,必须生成PIC代码动态链接用到一个重要概念:位置无关代码(Position-IndependentCode,PIC)GCC选项-fPIC指示生成PIC代码共享库代码是一种PIC共享库代码的位置可以是不确定的即使共享库代码的长度发生变化,也不影响调用它的程序引入PIC的目的链接器无需修改代码即可将共享库加载到任意地址运行先来看看所有可能出现的符号引用情况(1)模块内的过程调用、跳转,采用PC相对偏移寻址(2)模块内数据访问,如模块内的全局变量和静态变量(3)模块外的过程调用、跳转(4)模块外的数据访问,如外部变量的访问要实现动态链接,必须生成PIC代码调用或跳转源与目的地都在同一个模块,相对位置固定,只要用相对偏移寻址即可。call的目标地址为:0x8048369+0xffffffdb=0x8048344模块内的过程调用、跳转,采用PC相对偏移寻址动态链接用到一个重要概念:位置无关代码(Position-IndependentCode,PIC)GCC选项-fPIC指示生成PIC代码共享库代码是一种PIC共享库代码的位置可以是不确定的即使共享库代码的长度发生变化,也不影响调用它的程序引入PIC的目的链接器无需修改代码即可将共享库加载到任意地址运行先来看看所有可能出现的符号引用情况(1)模块内的过程调用、跳转,采用PC相对偏移寻址(2)模块内数据访问,如模块内的全局变量和静态变量(3)模块外的过程调用、跳转(4)模块外的数据访问,如外部变量的访问要实现动态链接,必须生成PIC代码voidtest(){a=1;……}模块内数据访问,如模块内的全局变量和静态变量动态链接用到一个重要概念:位置无关代码(Position-IndependentCode,PIC)GCC选项-fPIC指示生成PIC代码共享库代码是一种PIC共享库代码的位置可以是不确定的即使共享库代码的长度发生变化,也不影响调用它的程序引入PIC的目的链接器无需修改代码即可将共享库加载到任意地址运行库内定义的符号,库外用户程序进行符号引用模块外的数据访问,如外部变量的访问模块外的过程调用、跳转要实现动态链接,必须生成PIC代码要生成PIC代码,主要解决这两个问题位置无关代码的实现原理是基于以下事实:可执行文件的代码段中指令和数据段中的变量之间,相对地址偏移是固定的即与绝对存储器位置无关的数据段总是紧跟着代码段之后!全局变量引用位置无关全局偏移量表GOT在数据段:为每个全局变量引用增加一个条目每个条目有一个重定位记录可执行文件加载时,对全局变量进行重定位GOT[0]~GOT[3]是内置的表项设若addvec函数引用全局变量addcntGOT全局偏移表(GlobalOffsetTable,GOT)主要作用就是支持动态链接共享库和位置无关代码GOT本质是一个地址数组,其每一个条目(“槽”)包含一个指向函数或变量的地址链接时:链接器在创建可执行文件时会创建GOT。加载时:当程序被加载到内存中时,动态链接器会更新GOT中的某些条目。这包括解析外部函数和变量的地址,并将这些地址写入相应的GOT槽中。运行时:程序在运行时可能会通过GOT表来访问外部函数和变量。通过间接寻址实现的——代码不是直接跳转到目标地址,而是跳转到GOT中相应的条目,然后从该条目中读取实际地址并跳转到该地址。GOT全局偏移表(GlobalOffsetTable,GOT)主要作用就是支持动态链接共享库和位置无关代码GOT本质是一个地址数组,其每一个条目(“槽”)包含一个指向函数或变量的地址链接时:链接器在创建可执行文件时会创建GOT。加载时:当程序被加载到内存中时,动态链接器会更新GOT中的某些条目。这包括解析外部函数和变量的地址,并将这些地址写入相应的GOT槽中。运行时:程序在运行时可能会通过GOT表来访问外部函数和变量。通过间接寻址实现的——代码不是直接跳转到目标地址,而是跳转到GOT中相应的条目,然后从该条目中读取实际地址并跳转到该地址。.dynamic段里面保存:动态链接器所需要的基本信息,比如依赖于哪些共享对象、动态链接符号表的位置、动态链接重定位表的位置、共享对象初始化代码的地址等R_386_GLOB_DAT是一个x86架构下的重定位类型,用于在程序运行时将全局符号与其定义绑定。当使用该重定位类型时,链接器会在可执行文件中创建一个GOT(GlobalOffsetTable)表项,并将该表项的值设置为指向该全局符号的地址R_386_JUMP_SLOT是一个x86架构下的重定位类型,用于在程序运行时将PLT(ProcedureLinkageTable)表项与它们的定义绑定。当使用该重定位类型时,链接器会在可执行文件中创建一个PLT表项,并将该表项的值设置为跳转指令,用于调用相应的函数名(符号)。函数引用位置无关过程链接表(PLT)由编译器创建,处于代码段中:PLT[0]用于调用动态链接器;PLT[1]用于跳转到__libc_start_main函数执行初始化工作;从PLT[2]开始为函数引用的表项,每个函数引用对应一个表项.got用来保存全局变量引用的地址;.got.plt用来保存函数引用的地址,即对于外部函数的引用全部被分离出来放到了“.got.plt”中调用函数addvec()函数引用位置无关访问PLT[n],n>1将待重定位符号(此处为共享库内定义放入函数名)id(查看.rel.plt内容可知)入栈跳转到PLT[0],入栈.dynamic

section内容根据重定位表和重定位函数找到所需函数名对应的符号值(地址)改写对应.plt.got内容为函数地址调用函数addvec()函数引用位置无关过程链接表(PLT)由编译器创建,处于代码段中:PLT[0]用于调用动态链接器;PLT[1]用于跳转到__libc_start_main函数执行初始化工作;从PLT[2]开始为函数引用的表项,每个函数引用对应一个表项.got用来保存全局变量引用的地址;.got.plt用来保存函数引用的地址,即对于外部函数的引用全部被分离出来放到了“.got.plt”中调用函数addvec()&addvec第二次调用addvec()时,直接控制传递到PLT[2],通过GOT[4]间接跳转控制转移到addvec()函数动态链接器本身是动态链接还是静态链接?动态链接器本身是用来帮助其他ELF文件解决共享对象依赖问题的,必须不能依赖于其他共享对象!可执行文件PLT表GOT表

库中函数

加载时动态链接程序头表中有一个特殊的段:INTERP其中记录了动态链接器目录及文件名ld-linux.so运行时的动态链接#include<stdio.h>#include<dlfcn.h>intx[2]={1,2};inty[2]={3,4};intz[2];intmain(){void*handle;void(*addvec)(int*,int*,int*,int);char*error;

/*dynamicallyloadthesharedlibthatcontainsaddvec()*/handle=dlopen("./libvector.so",RTLD_LAZY);if(!handle){ fprintf(stderr,"%s\n",dlerror());

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论