在计算机领域中,地址无关代码 (position-independent code,PIC),又称地址无关可执行文件 (position-independent executable,PIE) ,是指可在主存储器中任意位置正确地运行,而不受其绝对地址影响的一种机器码。PIC广泛使用于共享库,使得同一个库中的代码能够被加载到不同进程的地址空间中。PIC还用于缺少内存管理单元的计算机系统中,使得操作系统能够在单一的地址空间中将不同的运行程序隔离开来。
定义地址无关代码(PIC)是指运行和放置地址无关的代码。 其实这里PIC是一个相对意思,因为生成代码或多或少都使用了位置无关代码,该实现的基本思想是:把指令中需要修改的部分分离出来,跟数据部分放在一起,这样指令部分就可以保持不变,而数据部分则在每个进程拥有一个副本。地址无关代码能够在不做修改的情况下被复制到内存中的任意位置。这一点不同于重定位代码,因为重定位代码需要经过链接器或加载器的特殊处理才能确定合适的运行时内存地址。 地址无关代码需要在源代码级别遵循一套特定的语义,并且需要编译器的支持。那些引用了绝对内存地址的指令(比如绝对跳转指令)必须被替换为PC相对寻址指令。这些间接处理过程可能导致PIC的运行效率下降,但是大多数处理器对PIC都有很好的支持,使得这效率上的这一点点下降基本可以忽略。
动态库动态库又称动态链接库英文为DLL,是Dynamic Link Library 的缩写形式,DLL是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。动态链接库和动态链接是重要的软件运行机制,它既是多个进程共享资源的主要方式,也是操作系统向应用程序提供系统服务的主要手段。动态链接主要有2个特点:动态的加载,当运行模块在需要的时候才将动态链接库加载映射入运行模块的虚拟地址空间;动态的解析,只有当要调用的函数被调用的时候,才会把这个函数在虚拟内存空间的起始地址解析出来。除了资源共享这个最基本的目的之外,利用动态链接机制还可实现共享库重定向等重要应用。动态库一般存放系统运行过程中所产生的所有信息、原始数据、用户输入的信息、推理的中间结果以及推理过程的纪录1。
例如Linux下的动态链接库文件是ELF格式的。Linux的动态链接实现机制引入了全局偏移 表和过程链接表,实现了位置无关代码(PIC)。同时,ELF文件的分层管理模型在Linux 动态链接机制中也起着重要的作用。ELF 格式的共享库使用 PIC 技术使代码和数据的引用与地址无关,程序可以被加载到地址空间的任意位置。PIC 在代码中的跳转和分支指令不使用绝对地址。PIC 在 ELF 可执行映像的数据段中建立一个存放所有全局变量指针的全局偏移量表。
引用问题与地址无关的代码,也就是需要考虑代码中会对地址进行引用的情况,共享对象(GCC中的动态链接文件)中地址引用可以分为以下几种情况:模块内函数调用、跳转等、模块内数据的访问,如模块内定义的静态变量,全局变量等、模块外部的函数调用、跳转等和模块外部的数据的访问,比如别的模块定义的全局变量。
模块(动态链接文件)内部的函数的调用:由于此时调用者与被调者都是位于同一个模块,所以调用者与被调者之间的相对位置是固定的,因此,对被调者的调用就可以使用相对地址来替代绝对地址,对于这种指令就是不需要重定位的。
模块内部的数据调用:与上面分析同理,由于数据定义与引用指令是位于同一个模块的,因此它们之间的相对位置是固定的。但是此时有一些区别,现代体系结构中,数据的相对寻址没有基于当前指令的寻址方式,因此ELF采用了一个巧妙的方法来获取当前PC(程序计数器)的值,再在该基础上添加一个偏移,即可访问到变量。
模块外部的函数的调用:此时对外部符号的引用显然是与地址有关的,按照先前说的基本思想,此时需要将与地址相关的部分放到数据段里。ELF 的做法是在数据段中建立一个指向这些函数的指针数组,也即是全局偏移表(GOT,Global Offset Tabel),当代码需要引用这些外部函数时,则可以通过GOT 中的相对应的项间接引用。动态链接器在装载模块的时候会查找每个函数所在地址,并填充GOT中的各个表项,以保证每个指针均指向正确的地址。同时由于GOT本身是放在数据段的,因此它可以在模块装载的时候被修改,并且每个进程都可有自己的副本。
模块外部的数据的调用:该方法与模块外部的函数访问方法相同,同样引入 GOT ,只是此时GOT 的表项中存储的是变量的地址。
机器语言机器语言(machine language)是一种指令集的体系。这种指令集称为机器码(machine code),是计算机的CPU可直接解读的数据。机器码有时也被称为原生码(Native Code),这个名词比较强调某种编程语言或库与运行平台相关的部分。
机器语言是用二进制代码表示的计算机能直接识别和执行的一种机器指令的集合。它是计算机的设计者通过计算机的硬件结构赋予计算机的操作功能。机器语言具有灵活、直接执行和速度快等特点。不同种类的计算机其机器语言是不相通的,按某种计算机的机器指令编制的程序不能在另一种计算机上执行。
要用机器语言编写程序,编程人员需首先熟记所用计算机的全部指令代码和代码的涵义。手编程序时,程序员要自己处理每条指令和每一数据的存储分配和输入输出,还需记住编程过程中每步所使用的工作单元处在何种状态。这是一件十分繁琐的工作,编写程序花费的时间往往是实际运行时间的几十倍或几百倍。而且,这样编写出的程序完全是0与1的指令代码,可读性差且容易出错。在现今,除了计算机生产厂家的专业人员外,绝大多数程序员已经不再学习机器语言。
本词条内容贡献者为:
李岳阳 - 副教授 - 江南大学