装载、链接与库总结

程序员的自我修养///


1.静态链接是在生成可执行程序的时候就把库中的内容加入到程序中。
载入时动态链接是在将功能模块读入内存时把动态库中调用到的相关模块的内容载入内存。
运行时动态链接是在执行程序调用到模块内容时再将动态库中的相应模块载入到内存。


2、编译生成的目标文件是未经链接的中间文件,从结构上讲是可执行文件,只是没有经过链接,有些地址和符号没有调整
是按照可执行文件格式存储,与真正的可执行文件结构不同,可执行文件覆盖程序编译、链接、装载、执行各个方面


3、ELF:可执行文件格式,在计算机科学中,是一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件。
是UNIX系统实验室(USL)作为应用程序二进制接口(Application Binary Interface,ABI)而开发和发布的,也是Linux的主要可执行文件格式。
1999年,被86open项目选为x86架构上的类Unix操作系统的二进制文件标准格式,用来取代COFF。因其可扩展性与灵活性,也可应用在其它处理器、计算机系统架构的操作系统上。


4.java编译:java源代码(符合语言规范)-->javac-->.class(二进制文件)-->jvm-->机器语言(不同平台不同种类)
如何让java的语法规则适应java虚拟机的语法规则?这个任务由javac编译器来完成java语言规范转换成java虚拟机语言规范。


5链接的接口——符号
在链接中,将函数和变量称为符号,函数名和变量名称为符号名
C++符号名称经过修饰防止重名,函数经过签名用来识别不同的函数


6、中间件:介于操作系统和应用程序之间的产品,中间件简单解释
你可以理解为面向信息系统交互,集成过程中的通用部分的集合,屏蔽了底层的通讯,交互,连接等复杂又通用化的功能,以产品的形式提供出来,系统在交互时,直接采用中间件进行连接和交互即可,避免了大量的代码开发和人工成本。其实,理论上来讲,中间件所提供的功能通过代码编写都可以实现,只不过开发的周期和需要考虑的问题太多,逐渐的,这些部分,以中间件产品的形式进行了替代






7、静态链接把目标文件的相似段合并,链接器为目标文件分配地址和空间(只关注于虚拟地址空间的分配)


8、不同编译器编译结果怎么链接到一起?
目标文件是同样是文件格式、同样的符号修饰标准、变量内存分布相同、函数调用方式相同等等,这些跟可执行代码二进制相关的内容称为ABI(连接器从链接库中查找)
ABI(Application Binary Interface): 应用程序二进制接口 描述了应用程序和操作系统之间,一个应用和它的库之间,或者应用的组成部分之间的低接口。
API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。定义了源代码和库之间的接口,是操作系统提供的,API 接口属于一种操作系统或程序接口。API 是一套协议,规定了我们与外界的沟通方式:如何发送请求和接收响应。


9、BFD库Binary File Discriptor Library:通过一个统一的接口处理不同的目标文件格式。BFD把目标文件抽象成一个统一的模型。现在GCC(编译器)、链接器Id、调试器等都是通过BFD库处理目标文件


10、使用ID链接脚本


11、PE是COFF文件的一种扩展,在window平台


12、映像:PE文件在装载时直接映射到进程的虚拟空间中执行,它是进程的虚拟空间的映像,所以PE文件也常被叫做映像文件


13、装载:将程序运行所需要的指令和数据全都装入内存,这是简单的静态装入。将常用的部分留在内存,不常用的放在磁盘,这是动态装入
    覆盖装载和页映射是两种常见的动态装载。都是用到程序的局部性原则,用到的模块装入内存,暂时不用的存放磁盘
覆盖装载:把一些不会相互调用的模块用公用内存,使用时覆盖管理器覆盖其他的
页映射:把一些用到的模块映射到内存中,用不到的装载管理器放弃。装载管理器使用一定算法(如先进先出法)。这个装载管理器就是现代操作系统
精确叫操作系统存储管理器。现在主流的操作系统就是使用这种方式装载可执行文件。window的PE文件和linux的ELF文件都是这种方法装载文件


14、MMU:是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件机制的内存访问授权,多用户多进程操作系统。


15、进程的建立:建立一个进程,装载相应的可执行文件并且执行。
(1)创建独立的虚拟地址空间。实际上是创建映射函数所需要数据结构或者是页目录
(2)读取可执行文件头,并且创建虚拟空间与可执行文件的映射关系。就是装载的过程,装载是一个虚拟空间映射过程,所以可执行文件也叫映像文件
(3)将CPU的指令寄存器设置为可执行文件的入口地址,启动运行。寄存器把控制权交给进程


16、ELF装载时把相同权限的合并一起映射,这样减少映射页节省内存


17、操作系统通过给进程空间划分一个个VMA(虚拟地址空间)来管理进程的虚拟空间:基本原则是将相同权限属性、有相同映像文件的映射成一个VMA
如:代码VMA,数据VMA,堆VMA,栈VMA


18、动态链接的思想是把程序按照模块拆分成各个独立的部分,在程序运行时才把他们链接成一个单独的可执行文件


19、动态链接和静态链接:
 静态连接库就是把(lib)文件中用到的函数代码直接链接进目标程序,程序运行的时候不再需要其它的库文件;动态链接就是把调用的函数所在文件模块(DLL)和调用函数在文件中的位置等信息链接进目标程序,程序运行的时候再从DLL中寻找相应函数代码,因此需要相应DLL文件的支持。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。
关于模块:
在静态链接中,整个程序只有一个可执行文件是一个不可分割的整体,在动态链接中,把程序即可执行文件和程序所依赖的共享对象看成程序的一个模块。共享对象的最终装载地址在编译时不确定,而是装载的时候动态的分配的


20、装载重定位:
为了使共享对象在任意地址装载,想到静态链接中的重定位。思路是在链接中对所有绝对地址引用不做重定位,而在装载时才完成。一旦模块地址确定,即目标地址确定,则系统对程序中所有的绝对地址引用重定位


21、装载重定位解决动态模块绝对地址引用的方法,但是指令无法在多个线程共享,希望把共享指令在装载时不需要因为装载地址改变而改变,思路就是把指令中需要被修改的部分分离出来跟数据部分放一起,这样指令部分不变,数据部分可以在每个线程拥有一个副本。称为地址无关代码技术
产生地址无关代码并不麻烦,我们把共享对象模块地址引用按照是否跨模块分为模块内部引用和模块外部引用,按照引用方法分为指令引用和数据访问。模块内部调用或者数据访问都是相对寻址。模块间访问因为地址相关的部分放到数据段里面,数据段建立一个指向这些变量的指针数组


22、延迟绑定:动态链接下模块间在程序执行前花费很多事时间用于函数符号的引用以及重定位,延迟绑定是函数第一次调用的时候才加载


23、在动态链接下,操作系统会先启动动态链接器。linux动态链接器是一个共享对象,操作系统通过映射方式加载到进程地址空间,加载完动态链接器后把控制权交到链接器入口。


24、动态链接器的步骤与实现::启动本身-装载共享对象-重定位与初始化
(1)动态链接器自举:
自举:计算机必须具备自举能力将自己所有的元件激活,以便能完成加载操作系统这一目的,然后再由操作系统承担起那些单靠自举代码无法完成的更复杂的任务。
动态链接器的自举必须满足本身不依赖其他对象,并且本身变量重定位由它自己完成。前一个条件可以在编写时不适用任何系统库和运行库,第二条件不用到自身变量。
(2)共享对象装载:
完成自举后,将可执行文件和本身符号合并到一个符号表中,称为全局符号表,然后开始寻找可执行文件所以来共享对象。链接器把共享对象装载一个集合中,依次加载,然后把代码和数据映射到进程中,其中所依赖的共享对象也加载
(3)重定位初始化:
重定位后要是共享对象有init段则执行,完成初始化


25、显示运行时链接:动态链接旺旺支持更加灵活的模块加载方式,叫显示运行时链接,也叫运行时加载。也就是程序运行时加载模块,不用时卸载。
   动态装载库:不需进行修改就可以运行装载的共享对象。比如一些插件、驱动


26、linux在执行可执行文件时会启动动态链接器,会查找共享库系统共享库
   环境变量:linux有改变动态链接器装载共享路径的方法。LD_LIVRARY_PATH:环境变量,进程启动时动态链接器查找共享库时会先加载环境变量指定路径。


WINDOW应用
27、window下动态链接库DDL(Dynamic Link Library),相当于linux共享对象。DDL更加强调模块化,使各个模块更加松散的组合、重用和升级。所以window很多通过升级DDL形式自我完善,升级到一定程度我们称为软件更新包。早期的window进程没有独立空间,都可以调用DDL,这种没有权限的访问容易使DDL数据损坏


28、基地址和相对地址:PE文件被装载时,其进程地址空间的起始地址就是基地址,它是优先被装载的,相对地址是相对于基地址的偏移
   window提供API实现进程间通讯,其中就有通过DLL实现。每个DLL在各个进程是独立的,都拥有自己副本,但是window可以把一些共享的DLL数据分离出来,设置为共享的,这样一个DLL有两个数据段,一个共享一个私有的


29、导出表:在DLL中,动态链接所需要的符号集中放在导出表的结构中,提供了一个符号名和符号地址的映射关系,通过符号查找相应的地址。导入函数绑定,导入函数会在导入表中,下次不需要重新导入解析,这个是DLL优化
以前可能会用序号作为查找手段,但是修改,增加、删除都会改变,现在不用了


30、栈:经典计算机科学中,栈是一个特殊容器,存函数和局部变量等,数据入栈和出栈,先入后出原理。栈是向下增长,栈顶由esp寄存器定位,栈底固定。window默认栈空间1M
栈帧:栈保存函数调用所需要的维护信息称为堆栈帧或活动记录。包括函数返回地址和参数、临时变量、保存的上下文。
帧指针:一个函数活动记录由ebp和esp两个寄存器指定范围,esp指向栈顶端,也是活动顶端,ebp指向活动记录的一个固定位置,esp寄存器也称为帧指针。ebp是固定的位置,定位函数活动记录中的数据,把ebp压入栈中为了函数返回恢复以前的ebp的值。
调用惯例:函数参数的调用按照一定的约定叫做调用惯例。参数传递通常是栈传递,有些调用惯例还使用寄存器传递。


31、堆:管理堆空间的通常是程序的运行库。运行库向操作系统批发较大堆空间,然后零售给程序。通过批发防止多次频繁操作影响程序性能。
linux通常申请虚拟映射空间,称为匿名空间,用来作为堆空间。linux堆空间是连续的,window不是,window通过空间链表链接在一起
window类型linux申请虚拟映射空间,只是未必用于堆内存,申请空间必须为页的整数倍,window中有堆管理器管理


32、库:
操作系统层面,文件操作在linux中称为文件描述符,window称为句柄


运行时库:任何一个程序都需要庞大的代码来支撑,它包含入口函数和所依赖函数集合,这样的代码集合称为运行时库。glibc是C运行时库,glibc是早期分散的。MSVC的CRT是后期的分为动态链接和静态链接版本的,支持与否多线程版本,以及是否只支持C不支持C++,window也能用


33、TLS:线程局部存储:线程想要使线程独享,用到线程局部存储。用法是要定义一个全局变量为TLS类型,只要在定义前加上相应关键字。
window TLS会放在.data或.bss段
在window线程会建立一个关于线程信息的结构,叫做线程环境块,保存堆栈地址和线程ID等信息
window创建线程有两种方法:window API和MSVC CRT


34、系统调用:应用程序(运行库也是应用程序一部分)与操作系统内核之间的接口。window基于DLL机制,通过DLL堆系统调用进行包装,形成所谓windowAPI。这样应用程序与操作系统之间多一层,应用程序通过windowAPI调用


35特权级与中断:
特权级:现代CPU在截然不同特权级下命令分为用户模式和内核模式:也称为用户台和内核态,操作系统可以让不同的代码运行在不同的模式下限制他们全力,提高稳定和安全性
中断:中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。每个操作系统都会提供中断的接口
系统调用运行在内核态的,而应用程序基本运行在用户态,系统通过中断从用户态切换到内核态。
每一个中断对应一个中断号,称为中断处理程序。在内核中有一个中断向量表对应中断处理程序指针。


36、windowAPI:
windowAPI是window操作系统提供给应用程序开发者最底层、最直接与window打交道的接口。CRT是建立在windowAPI之上的。windowAPI是以DLL导出函数的形式暴露给应用程序开发者,微软把这些函数的文件头、导出库、相关文件和工具一起提供给开发者称为SDK(Software Development Kit)


深入理解java虚拟机///
1.虚拟机:
概论:计算机系统的这种抽象类似于面向对象编程(OOP)中的针对接口编程泛型(或者是依赖倒转原则),通过一层抽象提取底层实现中共性的部分,底层实现这个抽象并完成自己个性的部分。也就是说通过一个抽象层次来隔离底层的不同实现。虚拟机规范定义了这个虚拟机要完成的功能(也就是接口),底层的操作系统和硬件利用自己提供的功能来实现虚拟机需要完成的功能(实现)。通过运行在虚拟机之上,Java才具有很好跨平台特性。


定义:当Java虚拟机由主机操作系统上的软件实现时,Java程序通过调用本地方法和主机进行交互。Java方法由Java语言编写,编译成字节码,存储在class文件中。本地方法由C/C++/汇编语言编写,编译成和处理器相关的机器代码,存储在动态链接库中,格式是各个平台专有。所以本地方法是联系Java程序和底层主机操作系统的连接方式。


java 命令开始>>>>寻找 配置文件 定位需要的 .dll>>>>.ddl 初始化 JVM 虚拟机>>>>获得 native 接口>>>>找到main 方法运行
JVM的DLL是JVM的主要实现

你可能感兴趣的:(基础原理)