-
2018-06-04 18:50:31
区别这两个概念之前,要知道 重定位 的概念。
重定位,通常来说把在装入时对目标程序中指令和数据地址修改的过程称为重定位。
而静态重定位就是,在逻辑地址转换为物理地址的过程中,地址变换是在进程装入时一次完成的,以后不再改变。
优点:是无需增加硬件地址转换机构,便于实现程序的静态连接。在早期计算机系统中大多采用这种方案。
缺点:内存空间不能移动;各个用户进程很难共享内存中同一程序的副本
动态重定位:动态运行的装入程序把转入模块装入内存之后,并不立即把装入模块的逻辑地址进行转换,而是把这
种地址转换推迟到程序执行时才进行,装入内存后的所有地址都仍是逻辑地址。这种方式需要寄存器的支持,其中
放有当前正在执行的程序在内存空间中的起始地址。
优点:内存空间可以移动;各个用户进程可以共享内存中同一程序的副本。
缺点:增加了机器成本,而且实现存储管理的软件算法比较复杂。
更多相关内容 -
地址重定位:静态重定位和动态重定位
2019-04-24 09:06:18地址重定位就是操作系统将逻辑地址转变为物理地址的过程。。。也就是对目标程序中的指令和数据进行修改的过程 将逻辑地址空间重定位到物理地址空间的时机有三种: 1、程序编译连接时:符号绑定,各Obj模块的相对...地址重定位就是操作系统将逻辑地址转变为物理地址的过程。。。也就是对目标程序中的指令和数据进行修改的过程
将逻辑地址空间重定位到物理地址空间的时机有三种:
1、程序编译连接时:符号绑定,各Obj模块的相对虚拟地址空间 -->统一的虚拟地址空间;可指定一个BaseAddress以优化装载时的重定位
2、程序装入内存时: 虚拟地址空间 -->虚拟地址空间;如果映像文件中的Base Address 与实际装载的起始虚拟地址空间,不一致,则需要根据偏移量 重定位 重定位项表
3、程序执行时:虚拟地址空间 -->物理地址空间, MMU
以下内容转自:http://bbs.pediy.com/showthread.php?t=76876
在这之前我一直对地址重定位的细节不是很了解。以下文章摘自《操作系统原理DOS篇(第二版)》。是我目前看过的关于重定位的最好的文章。与大家分享 一下。
以下介绍程序是如何装入内存,从而变成在计算机内可执行的形式的。
在用汇编语言或高级语言编写的程序中,是通过符号名来访问子程序和数据的,我们把程序中符号名的集合叫做“名字空间”。汇编语言源程序经过汇编,或者高级语言源程序经过编译,得到的目标程序是以“0”作为参考地址的模块,然后多个目标模块由连接程序连接成一个具有统一地址的装配模块,以便最后装入内存中执行。我们把目标模块obj中的地址称为相对地址(或逻辑地址),而把相对地址的集合叫做“相对地址空间”或简单地叫做“地址空间”。此即1、程序编译连接时的重定位,也叫符号绑定。
装配模块虽然具有统一的地址空间,但它仍是以“0”作为参考地址,即是浮动的。要把它装入内存执行,就要确定装入内存的实际物理地址,并修改程序中与 地址有关的代码,这一过程叫做地址重定位。
地址空间的程序和数据经过地址重定位处理后,就变成了可由CPU直接执行的绝对地址程序。我们把这一地址集合称为“绝对地址空间”或“存储空间”。地址重定位完成的相对地址转换成内存的绝对地址工作又称为地址映射(map)、按照重定位的时机,可分为静态重定位和动态重定位。
重定位是由操作系统安排的。 在装入程序前,系统会计算未使用的内存,然后将程序装入,并记下开始地址。在执行有相对地址的指令时,会将所有的地址加个刚才记下的开始地址,就叫重定位。
一、静态重定位:程序装入内存时
静态重定位是在程序执行之前进行重定位,它根据装配模块将要装入的内存起始位置,直接修改装配模块中的有关使用地址的指令。
例如,一个以“0”作为参考地址的装配模块(程序可以也可以在编译连接时指定一个Base Address基地址(虚拟地址空间),并完成以此Base Address为参考地址的重定位,这样在装载时,如果实际的装载起始地址(虚拟地址空间)和Base Address相同,就无需再进行转载时的静态重定位),要装入以1000为起始地址的存储空间。显然,在装入之前要做某些修改,程序才能正确执行。例如,MOV EAX,[500]这条指令的意义,是把相对地址为500的存储单元内容1234装入EAX号累器。现在内容为1234的存储单元的实际地址为1500, 即为相对地址(500)加上装入的地址(1000),因此,MOV EAX,[500]这条指令中的直接地址码也要相应地加上起始地址,而成为MOV EAX,[1500]。
程序中涉及直接地址的每条指令都要进行这样的修改。需要修改的位置称为重定位项,所做的加实际装入模块起始地址修改中的块起始地址称为重定位因子。
为支持静态重定位,连接程序在生成统一地址空间和装配模块时, 应产生一个重定位项表,连接程序此时还不知道装配模块将要装入的实际位置,故重定位表 所给出的需修改位置是相对地址所表示的位置。
操作系统的装入程序要把装配模块和重定位项表一起装入内存。由装配模块的实际装入起始地址得到重定位因子,然后实施如下两步:
(1)取重定位项,加上重定位因子而得到欲修改位置的实际地址;
(2)对实际地址中的内容再做加重定位因子的修改,从而完成指令代码的修改。
对所有的重定位项实施上述两步操作后,静态重定位才完成,尔后可启动程序执行。使用过的重定位项表内存副本随即被废弃。静态重定位有着无需硬件支持的优点,但存在着如下的缺点:一是程序重定位之后就不能在内存中搬动了;二是要求程序的存储空间是连续的,不能把程序放在若干个不连续的区域内。
如图:
二、动态重定位:程序执行时
动态重定位是指,不是在程序执行之前而是在程序执行过程中进行地址重定位。更确切地说,是在CPU每次访问内存单元前才进行地址变换。动态重定位可使装配模 块不加任何修改而装入内存,但是它需要硬件——定位寄存器的支持。
程序的目标模块装入内存时,与地址有关的各项均保持原来的相对地址不进行任何修改。如MOV 1,[500]这条指令仍是相对地址500。当此模块被 操作系统调度到处理机上执行时,操作系统将把此模块装入的实际起始起始地址减去目标模块的相对基地址,然后将其差值装入定位寄存器中。当CPU取得一条访 问内存的指令时,地址变换硬件逻辑自动将指令中的相对地址与定位寄存器中的值相加,再依此和值作为内存绝对地址去访问该单元中的数据。
由此可见,进行动态重定位的时机是在指令执行过程中,每次访问内存前动态地进行。采取动态重定位可带来两个好处:
(1)目标模块装入内存时无需任何修改,因而装入之后再搬迁也不会影响其正确执行,这对于存储器紧缩、解决碎片问题是极其有利的;
(2)一个程序由若干个相对独立的目标模块组成时,每个目标模块各装入一个存储区域,这些存储区域可以不是顺序相邻的,只要各个模块有自己对应的定位寄存器就行。动态重定位技术所付出的代价是需要硬件支持。
如图:
总结:
静态地址重定位:即在程序装入内存的过程中完成,是指在程序开始运行前,程序中的各个地址有关的项均已完成重定位,地址变换通常是在装入时一次完成的,以后不再改变,故成为静态重定位。
优点:无需硬件支持
缺点:1)程序重定位之后就不能在内存中搬动了;2)要求程序的存储空间是连续的,不能把程序放在若干个不连续的区域中。
动态地址重定位:不是在程序执行之前而是在程序执行过程中进行地址重定位。更确切的说,是在每次访问内存单元前才进行地址变换。动态重定位可使装配模块不加任何修改而装入内存,但是它需要硬件一定位寄存器的支持。
优点:1)目标模块装入内存时无需任何修改,因而装入之后再搬迁也不会影响其正确执行,这对于存储器紧缩、解决碎片问题是极其有利的;2)一个程序由若干个相对独立的目标模块组成时,每个目标模块各装入一个存储区域,这些存储区域可以不是顺序相邻的,只要各个模块有自己对应的定位寄存器就行。
缺点:需要硬件支持。
-
静态链接、动态链接、静态重定位、动态重定位(2019.10.22)
2017-07-11 20:29:39重定位概念:程序在装入内存时将逻辑地址转换为物理地址。 重定位分类— 静态重定位:在程序装入内存时就将逻辑地址转换为物理地址 优势:操作简单,不需要额外的机构...动态重定位:在程序运行期间,需要某一内...重定位概念:程序在装入内存时将逻辑地址转换为物理地址。
重定位分类—
静态重定位:在程序装入内存时就将逻辑地址转换为物理地址
优势:操作简单,不需要额外的机构或操作。
劣势:程序一旦装入后地址就不可再改变,程序也不可以再移动,不利于内存空间的有效使用。各个程序很难共享同一副本。
动态重定位:在程序运行期间,需要某一内存数据时才进行重定位。
优势:程序占用的内存空间可变,能提高内存的利用效率。比较容易实现不同程序对同一副本的共同使用。
劣势:需要额外的硬件支持,增加了成本。
链接概念:各个模块独自编写、编译,然后由链接器将各个模块链接在一起,以解析模块间的访问和对库的访问。
静态链接:在程序装入内存之前完成链接工作,静态链接库里的指令最后都被包含在最终的EXE文件。
动态链接:动态链接库文件不会被包含在EXE文件里,EXE文件动态的引用动态链接库。
细分:
装载时动态链接:提前就已经知道程序要调用哪些模块,在编译时就在相应地方存放链接这些模块的信息,运行时对应去调用。
运行时动态链接:提前无法预知,完全等运行时决定调用哪个函数。
—————————————————————————————————————————————————————————
程序和数据装入内存时需对目标程序中的地址进行修改。这种把逻辑地址转变为内存的物理地址的过程叫重定位。
对程序进行重定位的技术按重定位的时机可分为两种:静态重定位和动态重定位。
1.静态重定位
静态重定位是在目标程序装入内存时,由装入程序对目标程序中的指令和数据的地址进行修改,即把程序的逻辑地址都改成实际的地址。对每个程序来说,这种地址变换只是在装入时一次完成,在程序运行期间不再进行重定位。
优点是:无需增加硬件地址转换机构,便于实现程序的静态连接。在早期计算机系统中大多采用这种方案。
缺点是:(1)程序的存储空间只能是连续的一片区域,而且在重定位之后就不能再移动。这不利于内存空间的有效使用。(2)各个用户进程很难共享内存中的同一程序的副本。
2.动态重定位
动态重定位是在程序执行期间每次访问内存之前进行重定位。这种变换是靠硬件地址变换机构实现的。通常采用一个重定位寄存器,其中放有当前正在执行的程序在内存空间中的起始地址,而地址空间中的代码在装入过程中不发生变化。
此工作由硬件地址映射机制来完成。硬件支持,软硬件结合完成) 硬件上需要一对寄存器的支持。程序放在不连续的实际物理空间中,要进行逻辑地址到物理地址的转换,实现动态重定位一般需要页式存储管理,页式存储管理用的不是寄存器,使用的是称为page table(页表)的数据结构page table记录了所有逻辑地址到物理地址的转换信息,进程切换的时候需要冲洗硬件上的page table 。
优点是:(1)程序占用的内存空间动态可变,不必连续存放在一处。(2)比较容易实现几个进程对同一程序副本的共享使用。
缺点是:需要附加的硬件支持,增加了机器成本,而且实现存储管理的软件算法比较复杂。
现在一般计算机系统中都采用动态重定位方法。链接:
一、分别编译与链接(Linking)
大多数高级语言都支持分别编译,程序员可以显式地把程序划分为独立的模块或文件,然后每个独立部分分别编译。在编译之后,由链接器把这些独立的片段(称为编译单元)“粘接到一起”。(想想这样做有什么好处?)
在C/C++中,这些独立的编译单元包括obj文件(一般的源程序编译而成)、lib文件(静态链接的函数库)、dll文件(动态链接的函数库)等。
静态链接方式:在程序执行之前完成所有的组装工作,生成一个可执行的目标文件(EXE文件)。
动态链接方式:在程序已经为了执行被装入内存之后完成链接工作,并且在内存中一般只保留该编译单元的一份拷贝。
二、静态链接库与动态链接库
先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。
静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该DLL不必被包含在最终的EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。
采用动态链接库的优点:(1)更加节省内存;(2)DLL文件与EXE文件独立,只要输出接口不变,更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性。
三、认识动态链接库
动态链接是相对于静态链接而言的。所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。换句话说,函数和过程的代码就在程序的exe文件中,该文件包含了运行时所需的全部代码。当多个程序都调用相同函数时,内存中就会存在这个函数的多个拷贝,这样就浪费了宝贵的内存资源。而动态链接所调用的函数代码并没有被拷贝到应用程序的可执行文件中去,而是仅仅在其中加入了所调用函数的描述信息(往往是一些重定位信息)。仅当应用程序被装入内存开始运行时,在Windows的管理下,才在应用程序与相应的DLL之间建立链接关系。当要执行所调用DLL中的函数时,根据链接产生的重定位信息,Windows才转去执行DLL中相应的函数代码。一般情况下,如果一个应用程序使用了动态链接库,Win32系统保证内存中只有DLL的一份复制品
动态链接库的两种链接方法:
(1) 装载时动态链接(Load-time Dynamic Linking):这种用法的前提是在编译之前已经明确知道要调用DLL中的哪几个函数,编译时在目标文件中只保留必要的链接信息,而不含DLL函数的代码;当程序执行时,调用函数的时候利用链接信息加载DLL函数代码并在内存中将其链接入调用程序的执行空间中(全部函数加载进内存),其主要目的是便于代码共享。(动态加载程序,处在加载阶段,主要为了共享代码,共享代码内存)
(2) 运行时动态链接(Run-time Dynamic Linking):这种方式是指在编译之前并不知道将会调用哪些DLL函数,完全是在运行过程中根据需要决定应调用哪个函数,将其加载到内存中(只加载调用的函数进内存),并标识内存地址,其他程序也可以使用该程序,并用LoadLibrary和GetProcAddress动态获得DLL函数的入口地址。(dll在内存中只存在一份,处在运行阶段)
上述的区别主要在于阶段不同,编译器是否知道进程要调用的dll函数。动态加载在编译时知道所调用的函数,而在运行态时则必须不知道。
重定位————————————————————————————————————————————————
连续分配方式,是指为一个用户程序分配一个连续的内存空间。
----- 可重定位分区分配
1、动态重定位的引入
在连续分配方式中,必须把一个系统或用户程序装入一连续的内存空间。如果在系统中只有若干个小的分区,即使它们的容量总和大于要装入的
程序,但由于这些分区不相邻接,也无法把该程序装入内存。这种不能被利用的小分区称为“零头”或“碎片”。
当内存中出现几个互不邻接的小分区,它们单独的容量不能满足作业的大小,但它们的容量总和大于作业的要求时,若想把作业装入,可采用的
一种方法是:将内存中的所有作业进行移动,使它们全部相邻接,这样,即可把原来分散的多个小分区拼接成一个大分区,这时就可把作业装入该区。
拼接(紧凑/紧缩)-- 这种通过移动内存中作业的位置,然后把原来多个分散的空闲小分区拼接成一个大分区的方法,称为“拼接”或“紧凑”。
所谓拼接是指移动内存(存储器)中所有已分配区到内存的一端,使本来分散的小空闲区连成一个大的空闲区。
---- 由于经过紧凑后的某些用户程序在内存中的位置发生了变化,此时若不对程序和数据的地址加以修改(变换),则程序必将无法执行。
为此,在每次“紧凑”后,都必须对移动了的程序或数据进行重定位。
---- 拼接时机(什么时候拼接):
第一种方案是在某个分区回收时立即进行拼接,这样在内存中总是只有一个连续的空闲区。但由于拼接很费时间,拼接频率过高会使系统开销加大。
第二种方案是当找不到足够大的空闲区且空闲区的总容量可以满足作业要求时进行拼接。拼接的频率比第一种要小得多,但空闲区的管理稍微复杂一些。
2、动态重定位的实现
---- 在动态运行时装入的方式中,作业装入内存后的所有地址都仍然是相对地址(逻辑地址),将相对地址转换为物理地址的工作,被推迟到程序指令
要真正执行时进行。为使地址的转换不会影响到指令的执行速度,必须有硬件地址变换机构的支持,即需在系统中增设一个重定位寄存器,用来存放
程序(数据)在内存中的起始地址。程序在执行时,真正访问的内存地址是相对地址与重定位寄存器中的地址相加而形成的。
---- 地址变换过程是在程序执行期间,随着对每条指令或数据的访问自动进行的,故称为动态重定位。
---- 当系统对内存进行了“紧凑”而使若干程序从内存的某处移至另一处时,不需对程序做任何修改,只需用该程序在内存的新起始地址,去置换原来的
起始地址即可。
3、动态重定位分区分配算法
---- 动态重定位分区分配算法与动态分区分配算法基本上相同,差别仅在于:在这种分配算法中,增加了紧凑功能。
---- 通常,在找不到足够大的空闲分区来满足用户需求时进行紧凑。
算法流程图如下:
4、分区的存储保护
---- 存储保护是为了防止一个作业有意或无意地破坏操作系统或其他作业。常用的存储保护方法有界限寄存器和存储保护键方法。
---- 采用界限寄存器方法实现存储保护又有两种方式:
1)上、下界寄存器方法。采用上、下界寄存器分别存放作业的结束地址和开始地址。在作业运行过程中,将每一个访问内存的地址都同这两个
寄存器的内容进行比较。在正常情况下,这个地址应大于下界寄存器,且小于上界寄存器的内容,如超出这个范围便产生保护性中断。
2)基址、限长寄存器方法。采用基址和限长寄存器分别存放作业的起始地址及作业的地址空间长度。当作业执行时,将每一个访问内存的
相对地址和这个限长寄存器比较,如果超过了限长,则发出越界中断信号,并停止作业的运行。
---- 存储保护键方法是给每个存储块分配一个单独的保护键,它相当于一把锁。存储块不同于分区,一个分区由若干个存储块组成,每个存储块
大小相同,一个分区的大小必须是存储块的整数倍。此外,进入系统的每个作业也被赋予一个保护键,它相当于一把钥匙。
当作业运行时,检查钥匙和锁是否一致,如果二者不匹配,则系统发出保护性中断信号,并停止作业的运行。
————————————————————————————————————————————
我们大家在编程过程中对“链接”这个词并不陌生,链接所解决的问题即是将我们自己写的代码和别人写的库集成在一起。链接可以分为静态链接与动态链接,下文将分别讲解这两种方式的特点与其区别。
- 静态链接
- 特点:在生成可执行文件的时候(链接阶段),把所有需要的函数的二进制代码都包含到可执行文件中去。因此,链接器需要知道参与链接的目标文件需要哪些函数,同时也要知道每个目标文件都能提供什么函数,这样链接器才能知道是不是每个目标文件所需要的函数都能正确地链接。如果某个目标文件需要的函数在参与链接的目标文件中找不到的话,链接器就报错了。目标文件中有两个重要的接口来提供这些信息:一个是符号表,另外一个是重定位表。
- 优点:在程序发布的时候就不需要的依赖库,也就是不再需要带着库一块发布,程序可以独立执行。
- 缺点:
-
- 程序体积会相对大一些。
- 如果静态库有更新的话,所有可执行文件都得重新链接才能用上新的静态库。
- 动态链接
- 特点: 在编译的时候不直接拷贝可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中,然后程序在运行到指定的代码时,去共享执行内存中已经加载的动态库可执行代码,最终达到运行时连接的目的。
- 优点: 多个程序可以共享同一段代码,而不需要在磁盘上存储多个拷贝。
- 缺点: 由于是运行时加载,可能会影响程序的前期执行性能。
- 库
上面的文章多次提到库(lib)这个概念,所谓的库就是一些功能代码经过编译连接后的可执行形式。
大家在Windows平台上见到的.dll文件和linux平台下so动态库都输入库。
库也有静态lib和动态lib之分:
-
-
- 静态lib将导出声明和实现都放在lib中。编译后所有代码都嵌入到宿主程序。
- 动态lib相当于一个h文件,是对实现部分(.dll文件)的导出部分的声明。编译后只是将导出声明部分编译到宿主程序中,运行时候需要相应的dll文件支持。
-
- 静态链接
-
uboot 代码重定位(位置有关码)(存储地址,运行地址,链接地址)
2021-01-20 11:16:192.4、链接地址和运行地址的区别 3、位置有关码,位置无关码详细解释 4、代码重定位 4.1、重定位代码详解 1、代码启动过程简要分析 问题1:代码下载到哪里去? 数据手册上会有说明,位置不是我们想往哪里下载就往... -
12. 重定位及动态链接
2018-12-07 17:28:3412.1 符号的重定位 1. 重定位步骤 2. 重定位信息 3. 重定位操作举例 (1)源文件 (2)链接结果 (3)R_386_PC32的重定位 main.o重定位前 R_386_PC32的重定位方式 (4) R_386_32的重定位 重定位前 R_386_...12.1 符号的重定位
1. 重定位步骤
2. 重定位信息
3. 重定位操作举例
(1)源文件
(2)链接结果
(3)R_386_PC32的重定位
main.o重定位前
R_386_PC32的重定位方式
(4) R_386_32的重定位
重定位前
R_386_32的重定位方式
swap.o重定位
重定位后
12.2 可执行文件的加载
1. 加载方法
(1)通过调用execve系统调用函数来调用加载器
(2)加载器(loader)根据可执行文件的程序(段)头表中的信息,将可执行文件的代码和数据从磁盘“拷 贝”到存储器中
(3)加载后,将PC(EIP)设定指向 Entry point(即符号_start处),最终执行main函数,以启动程序执行
ELF头信息举例
2. 程序的加载和运行
(1) UNIX/Linux系统中,可通过调用execve()函数来启动加载器。
(2) execve()函数的功能是在当前进程上下文中加载并运行一个新程序。 execve()函数的用法如下:
int execve(char *filename, char *argv[], *envp[]);
①filename:加载并运行的可执行文件名(如./hello)
②argv:可带参数列表
③envp:环境变量列表
若错误(如找不到指定文件filename) ,则返回-1,并将控制权交给调用程序;
若函数执行成功,则不返回 ,最终将控制权传递到可执行目标中的主函数main。
(3) 主函数main()的原型形式如下:
int main(int argc, char **argv, char **envp);
或者:int main(int argc, char *argv[], char *envp[]);
argc指定参数个数,参数列表中第一个总是命令名(可执行文件名)
例如:命令行为“ld -o test main.o test.o” 时,argc=63. 程序的加载和运行过程举例
Step1: 在shell命令行提示符后输入命令:$./hello[enter]
Step2: shell命令行解释器构造argv和envp
Step3: 调用fork()函数,创建一个子进程,与父进程shell完全相同( 只读/共享),包括只读代码段、可读写数据段、堆以及用户栈等。
Step4: 调用execve()函数,在当前进程(新创建的子进程)的上下文中加载并运行hello程序。将hello中的.text节、.data节、.bss节等内容加载到当前进程的虚拟地址空间(仅修改当前进程上下文中关于存储映像的一些数据结构,不从磁盘拷贝代码、数据等内容)
Step5:调用hello程序的main()函数,hello程序开始在一个进程的上下文中运行。int main(int argc, char *argv[], char *envp[]);12.3 共享库和动态链接
1. 动态链接的共享库(Shared Libraries)
静态库有一些缺点:
– 库函数(如printf)被包含在每个运行进程的代码段中,对于并发运行上百个进程的系统,造成极大的主存资源浪费
– 库函数(如printf)被合并在可执行目标中,磁盘上存放着数千个可执行文件,造成磁盘空间的极大浪费
– 程序员需关注是否有函数库的新版本出现,并须定期下载、重新编译和链接,更新困难、使用不便
解决方案: Shared Libraries (共享库)(1)共享库
① 是一个目标文件,包含有代码和数据
② 从程序中分离出来,磁盘和内存中都只有一个备份
③ 可以动态地在装入时或运行时被加载并链接
④ Window称其为动态链接库(Dynamic Link Libraries,.dll
文件)
⑤ Linux称其为动态共享对象(Dynamic Shared Objects,.so
文件)(2)共享库的动态链接与优点
动态链接可以按以下两种方式进行:
① 在第一次加载并运行时进行(load-time linking).
– Linux通常由动态链接器(ld-linux.so)自动处理
– 标准C库(libc.so) 通常按这种方式动态被链接
② 在已经开始运行后进行(run-time linking).
– 在Linux中,通过调用dlopen()等接口来实现(用于分发软件包、构建高性能Web服务器等)共享库的优点:
① 在内存中只有一个备份,被所有进程共享,节省内存空间
② 一个共享库目标文件被所有程序共享链接,节省磁盘空间
③ 共享库升级时,被自动加载到内存和程序动态链接,使用方便
④ 共享库可分模块、独立、用不同编程语言进行开发,效率高
⑤ 第三方开发的共享库可作为程序插件,使程序功能易于扩展(3) 自定义一个动态共享库文件
自定义库函数
//myproc1.c #include <stdio.h> void myfunc1() { printf("%s","This is myfunc1!\n"); } //myproc2.c #include <stdio.h> void myfunc2() { printf("%s","This is myfunc2\n"); }
生成库文件
$gcc -c myproc1.c myproc2.c //预处理、编译、汇编 $gcc -shared -fPIC -o mylib.so myproc1.o myproc2.o //生成位置无关的共享代码库文件mylib.so
2. 动态链接
(1)加载时的动态链接
(2)运行时的动态链接
可通过动态链接器接口提供的函数在运行时进行动态链接。类UNIX系统中的动 态链接器接口定义了相应的函数,如 dlopen, dlsym, dlerror, dlclose等, 其头文件为dlfcn.h。
#include <stdio.h> #include <dlfcn.h> int main() { void *handle; void (*myfunc1)(); char *error; /* 动态装入包含函数myfunc1()的共享库文件*/ handle = dlopen("./mylib.so", RTLD_LAZY); if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(1); } /* 获得一个指向函数myfunc1()的指针myfunc1*/ myfunc1 = dlsym(handle, "myfunc1"); if ((error = dlerror()) != NULL) { fprintf(stderr, "%s\n", error); exit(1); } /* 现在可以像调用其他函数一样调用函数myfunc1() */ myfunc1(); /* 关闭(卸载)共享库文件*/ if (dlclose(handle)< 0) { fprintf(stderr, "%s\n", dlerror()); exit(1); } return 0; }
3. 位置无关代码(PIC)
动态链接用到一个重要概念:
– 位置无关代码(Position-Independent Code,PIC )
– GCC选项 -fPIC 指示生成PIC代码
共享库代码是一种PIC
– 共享库代码的位置可以是不确定的
– 即使共享库代码的长度发生变化,也不影响调用它的程序
引入PIC的目的
– 链接器无需修改代码即可将共享库加载到任意地址运行
所有引用情况
(1) 模块内的过程调用、跳转,采用PC相对偏移寻址
(2) 模块内数据访问,如模块内的全局变量和静态变量
(3) 模块外的过程调用、跳转
(4) 模块外的数据访问,如外部变量的访问
要实现动态链接, 必须生成PIC代码 ;
要生成PIC代码,主要解决(3)(4)两个问题① 模块内的过程调用、跳转
② 模块内数据访问
③ 模块外的数据访问
④ 模块外的过程调用、跳转
-
操作系统---静态重定位和动态重定位
2018-03-10 16:28:49对程序进行重定位的技术按重定位的时机可分为两种:静态重定位和动态重定位。静态重定位:是在目标程序装入内存时,由装入程序对目标程序中的指令和数据的地址进行修改,即把程序的逻辑地址都改成实际的地址。对每个... -
聊聊Linux动态链接中的PLT和GOT(2)——延迟重定位
2016-06-11 17:00:26plt和got引入延迟重定位机制之后,方案复杂度就更高了。为了让大家对延迟机制有深入的理解,将Linux方案写成C语言伪代码。 -
编译过程和符号表重定位问题、静态和动态链接
2016-08-27 10:05:57编译过程和符号表重定位问题:转载至:点击打开链接 对于代码的编译问题千头万绪从何说起呢,首先来说一下计算机是如何处理应用程序的,实质上应用程序是通过操作系统来应用机器指令操控硬件设施完成各种任务的,... -
程序编译后的结构和动态编译重定位,程序编译知识
2017-06-25 17:29:43程序编译知识: 程序被编译后的结构模型如下,正文段(.text):由cpu执行的机器指令部分,通常正文段可共享、只读的;初始化数据段(.data):包含程序中需要赋初值得变量;...程序装入和重定位知 -
linux下elf重定位理解
2021-05-16 11:28:52准备:可重定位文件(Relocatable file),可执行文件(Executable file),共享文件(Shared object file)。Relocatable file: an object file that holds code and data suitable for linking with other object files ... -
7.7-11 重定位过程描述+可执行目标文件的加载+共享库动态链接
2021-01-20 23:49:14Relocatable object file(可重定位的对象文件). Contains binary code and data in a form that can be combined with other relocatable object files at compile time to create an executable object file. ... -
南大Mooc计算机体系基础--重定位和动态链接
2017-10-27 22:39:50重定位和动态链接 符号解析:得到E、D两个集合 重定位: 合并相同的节:把E中所有相同的节合并成新节 对D中定义符号确定位置:确定虚拟空间地址 对引用符号重定位:修改.text和.data节对符号的引用(地址) 重定位... -
重定位和链接
2016-07-10 11:32:44链接和重定位是嵌入式C中很重要的部分,对于这一块掌握的越精细越好。 指令位置分类 指令分为两种: 位置无关编码(PIC):汇编源文件被编码成二进制可执行程序时编码方式与位置(内存地址)无关 位置相关编码:... -
静态重定位与动态重定位
2017-04-24 20:58:07地址重定位就是操作系统将逻辑地址转变为物理地址的过程。。。也就是对目标程序中的指令和数据进行修改的过程 将逻辑地址空间重定位到物理地址空间的时机有三种: 1、程序编译连接时。 2、程序装入内存时。... -
动态重定位执行过程
2017-06-21 23:10:01ld-linux.so.2的_dl_runtime_resolve函数,这个函数解析出puts的绝对地址,回填到GOT[5]。 所有动态库函数在第一次调用时,都是通过XXX@plt...linux 动态链接器提供动态重位功能,所有外部函数只有调用时才做重定位 -
程序链接之符号解析和重定位
2022-04-06 17:00:02链接器在连接过程中的工作就是把多个输入的目标文件加工合并成一个输出文件。有几种不同的方案: 按序叠加 按序叠加可以说是最简单的一个方案,就是将输入的目标文件按照次序叠加起来。 从图中可以看到,在有很... -
为什么要动态链接,动态链接库和静态连接的区别与优势
2018-07-27 14:30:12静态链接使得不同的程序开发者和部门能够相对独立地开发和测试自己的程序模块,从某种意义上来讲大大促进了程序开发的效率,原先限制程序的规模也随之扩大。但是慢慢地静态链接的诸多缺点也逐步暴露出来,比如浪费... -
程序装入内存时的静态重定位与动态重定位【转】
2017-12-05 18:30:00在用汇编语言或高级语言编写的程序中,是通过符号名来访问子程序和数据的,我们把程序中符号名的集合叫做“名字空间”。汇编语言源程序经过汇编,或者高级语言源程序经过编译,得到的目标程序是以“0”作为参考... -
ARM裸机篇(四)——重定位和地址无关码
2022-04-14 21:13:26linux基础篇(二)——静态和动态链接 ARM裸机篇(一)——i.MX6ULL启动过程 ARM裸机篇(二)——i.MX6ULL第一个裸机程序 ARM裸机篇(三)——重定位和地址无关码 一、将程序重映射到RAM 在上一节中,我们将第一个... -
一种基于TI TMS320 DSP的软件动态链接技术
2021-04-16 17:58:51介绍了软件动态链接技术的概念和特点,提出了基于TI TMS320系列DSP的软件动态链接技术。该技术解决了可重配置的DSP系统中关于软件二进制目标代码的动态加载和卸载的问题。采用该技术的软件重配置方案已成功运用于某... -
【转】地址重定位:静态重定位和动态重定位
2012-05-03 15:42:36地址重定位就是操作系统将逻辑地址转变为物理地址的过程。。。也就是对目标程序中的指令和数据进行修改的过程 将逻辑地址空间重定位到物理地址空间的时机有三种: 1、程序编译连接时。 2、程序装入... -
静态链接和动态链接区别
2020-05-24 16:05:38最后进行汇编,这个过程比较简单,就是将对应的汇编指令翻译成机器指令,生成可重定位的二进制目标文件。以上就是编译的过程,下面主要介绍两种链接方式--静态链接和动态链接。 静态链接和动态链... -
重定位及动态链接
2017-10-28 17:58:47符号的重定位 可执行文件的加载 共享库和动态链接 -
什么是重定位?为什么需要重定位?
2018-06-15 17:30:151、链接地址和运行地址。①运行地址,顾名思义就是程序运行的时候的地址,也就是你用工具将代码下载到RAM的那个地址,也叫加载地址。②链接地址,由链接脚本指定的地址。为什么需要链接脚本指定地址呢?你想一下,在...