编译链接过程
文章平均质量分 88
boat_7
世人皆被命运安排,而我安排命运
展开
-
为什么要动态链接
为什么要动态链接内存和磁盘空间程序开发和发布动态链接静态链接使得不同的程序开发者和部门能够相对独立地开发和测试自己的程序模块,某种意义上来讲大大促进了程序开发的效率,原先限制程序的规模也随之扩大,但是慢慢的静态链接的诸多缺点也逐渐暴露出来,比如浪费内存和磁盘空间,模块更新困难等问题,使得人们不得不寻找一种更好的方式来组织程序的模块。内存和磁盘空间静态链接的方式对于计算机内存和磁盘的空间浪费非常严重,特别是多进程操作系统情况下,静态链接极大的浪费了内存空间,想象一下每个程序内部除了都保留着printf(原创 2021-06-26 20:04:31 · 176 阅读 · 1 评论 -
装载的方式
装载的方式程序执行时所需要的指令和数据必须在内存中才能够正常运行,最简单的方法就是将程序运行所需要的指令和数据全部装入内存中,这样程序就可以顺利进行,这就是最简单的静态装入的方法,但是很多情况下程序所需要的内存数量大于物理内存的数量,当内存的数量不够时,根本的解决办法就是添加内存,相对于磁盘来说,内存是昂贵且稀有的,这种情况自计算机诞生以来一直如此,所以人们想尽各种办法,希望能够在不添加内存的情况下让更多的程序运行起来,尽可能有效的利用内存,后来研究发现,程序运行时有局部性原理的,所以我们可以将程序最常用原创 2021-06-25 22:27:48 · 528 阅读 · 0 评论 -
C++相关问题-重复代码消除
重复代码消除C++编译器在很多时候会产生重复的代码,比如模板,外部内联函数和虚函数表都有可能在不同的编译单元里生成相同的代码。最简单的情况就拿模板来说,模板从本质上来讲很像宏,当模板在一个编译单元里被实例化时,它并不知道自己是否在别的编译单元也被实例化了。所以当一个模板在多个编译单元同时被实例化成相同的类型的时候,必然会生成重复的代码,把这些重复的代码保留下来会存在以下几个问题:空间浪费。地址较易出错。有可能两个指向同一个函数的指针会不相同。指令运行效率较慢。因为现代的CPU都会对指令和数据进行缓原创 2021-06-24 13:13:31 · 1220 阅读 · 0 评论 -
符号解析与重定位
重定位//a.cextern int shared;int main(){ int a = 100; swap(&a, &shared);}//b.cint shared = 1;void swap(int* a, int* b){ *a ^= *b ^= *a ^= *b;}将"a.c"和"b.c"分别编译成目标文件"a.o"和"b.o"。在完成空间和地址的分配步骤以后,链接器就进入了符号解析与重定位的步骤,这也是静态链接的核心内容,,在分析符号解析和重定原创 2021-06-16 16:02:02 · 509 阅读 · 0 评论 -
深入剖析虚拟内存笔记2
加速翻译和优化页表之前我们了解了虚拟内存及其分页和地址翻译的基础和原理,现在我们可以引入虚拟内存中两个核心的需求,或者瓶颈:1.虚拟地址到物理地址的映射过程必须非常快,地址翻译如何加速。2.虚拟地址范围的增大必然会导致页表的膨胀,形成大页表。我们依然引用之前的话:计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。因此,虽然虚拟内存本身已经是一个中间层了,但是中间层的问题同样可以通过再引入一个中间层来解决。加速地址翻译过程的方案目前是通过引入页表缓存模板-TLB,而大页表则是通过实现多级原创 2021-06-15 11:35:32 · 88 阅读 · 0 评论 -
深入剖析虚拟内存工作原理笔记
虚拟内存计算机存储器主存物理内存虚拟内存虚拟内存是当今计算机系统中最重要的抽象概念之一,它的提出是为了更加有效地管理内存并且降低内存出错的概率。计算机存储器存储器是计算机的核心部位之一,在完全理想状态下,存储器应该具备以下三个特性:1.速度足够快。2.容量足够大。3.价格足够便宜。但是现实很残酷,我们当前的计算机技术无法同时满足上述的三个条件,于是现代计算机的存储器设计采用了一种分层次的结构:从顶至底,现代计算机里的存储器类型分别为:寄存器,高速缓存,主存和磁盘,这些存储器的速度逐级递减而容量逐原创 2021-06-14 00:52:42 · 407 阅读 · 2 评论 -
空间与地址分配
空间与地址分配按序叠加相似段合并符号地址的确定当我们有两个目标文件的时候,如何将它们链接起来形成一个可执行文件?这个过程发生了什么?这基本上就是链接的核心内容:静态链接。我们将使用两个源代码文件"a.c"和"b.c"作为例子展开分析://a.cextern int shared;int main(){ int a = 100; swap(&a, &shared);}`````cpp//b.cint shared = 1;void swap(int* a, int原创 2021-06-09 21:38:43 · 267 阅读 · 0 评论 -
链接的接口-符号
链接的接口-符号链接过程的本质就是要把多个不同的目标文件之间相互粘在一起,或者说像玩具积木一样,可以拼接形成一个整体,为了使不同目标文件之间能够相互粘合,这些目标文件之间必须有固定的规则才行,就像积木模块必须有凹凸部分才能够相互拼合,在链接中,目标文件之间相互拼合实际上是目标文件对地址的引用,即对函数和变量的地址的引用,比如目标文件B要用到了目标文件A中的函数"foo",那么我们就称目标文件A定义了函数"foo",那么我们就称目标文件A定义了函数"foo",称目标文件B引用了目标文件A中的函数"foo",原创 2021-05-15 21:42:03 · 299 阅读 · 0 评论 -
挖掘SimpleSection.o
挖掘SimpleSection.o前面对于目标文件只是作了概念上的阐述,如果不彻底深入目标文件的具体细节,相信这样的分析也是泛泛而谈,没有真正深入理解的效果,本节的内容就是以ELF目标文件格式作为例子,彻底深入剖析目标文件,争取不放过任何一个字节。真正了不起的程序员对自己的程序的每一个字节都了如指掌我们就以前面提到的SimleSection.c编译出来的目标文件作为分析对象程序代码如清单所示:SimpleSection.cLinux: gcc -c SimpleSection.cWin原创 2021-05-03 22:08:16 · 166 阅读 · 0 评论 -
目标文件里有什么
目标文件目标文件格式目标文件是什么样的编译器编译源代码后生成的文件叫做目标文件,那么目标文件里面到底存放的是什么,或者我们的源代码在经过编译以后是怎样存储的?我们将去探索它本质的东西。目标文件从结构上讲,它是已经被编译后的可执行文件格式,只是还没有经过链接的过程,其中可能有些符号或有些地址还没有被调整。其实它本身就是按照可执行文件格式存储的,只是跟真正的可执行文件在结构上稍有不同。可执行文件格式涵盖了程序的编译,链接,装载和执行的各个方面,了解它的结构并深入剖析对于认识系统,了解后面的机理大有好处。原创 2021-05-02 19:58:24 · 135 阅读 · 0 评论 -
链接笔记
经过这些扫描,语法分析,语义分析,源代码优化,代码生成和目标代码优化,编译器忙活了这么多个步骤后,源代码终于被编译成了目标代码,但这个目标代码有一个问题:index和array的地址还没有确定。如果我们把目标代码使用汇编器编译成真正能够在机器上执行的指令,那么index和array的地址应该从哪得到?如果index和array定义在跟上面的源代码同一个编译单元里面,那么编译器可以为index和array分配空间,确定他们的地址,那如果是定义在其他的程序模块中呢“?事实上,定义其他模型的全局变量和函数在最终原创 2021-04-29 13:58:35 · 99 阅读 · 2 评论 -
编译器做了什么
编译器从最直观的角度来讲,编译器就是将高级语言翻译成机器语言的一个工具,比如我们用C/C++语言写的一个程序可以使用编译器将其翻译成机器可以执行的指令及数据。使用机器指令或汇编语言编写程序是十分费事及乏味的事情,它们使得程序开发的效率十分低下,并且使用机器语言或汇编语言编写的程序依赖于特定的机器,一个为某种CPU编写的程序在另外一种CPU下完全无法运行,要重新编写,这几乎是令人无法接受的。所以人们期望能够采用类似于自然语言的语言来描述一个程序,但是自然语言的形式不够精确,所以类似于数学定义的编程语言很快就原创 2021-04-26 22:22:52 · 480 阅读 · 4 评论 -
编译和链接笔记
编译和链接被隐藏了的过程对于平常的应用程序开发,我们很少需要关注编译和链接过程,因为通常的开发环境都是流行的集成开发环境(IDE),比如visual studio等,这样的IDE一般都将编译和链接的过程一步完成,通常将这种编译和链接合并在一起称为构建。即使使用命令行来编译一个源代码文件,简单的一句"hello.c"就包含了非常复杂的过程。IDE和编译器提供的默认设置,编译和链接参数对于大部分的应用程序开发而言已经足够使用了,但是在这样的开发过程中,我们往往会被这些复杂的集合工具所提供的强大功能所迷惑,很原创 2021-04-23 17:20:05 · 77 阅读 · 0 评论 -
线程笔记
线程线程的访问权限线程调度与优先级可抢占线程和不可抢占线程线程安全竞争和原子操作线程,有时被称为轻量级进程,是程序执行流的最小单位,一个标准的线程由线程ID,当前指令指针,寄存器集合,堆栈组成。通常意义上,一个进程由一个到多个线程组成,各个线程之间共享程序的内存空间(包括代码段,数据段,堆等)及一些进程级的资源(如打开文件和信号)。使用多线程的原因如下:1.某个操作可能会陷入长时间等待,等待的线程会进入睡眠状态,无法继续执行,多线程执行可以有效利用等待的时间,典型的例子就是等待网络响应,这可能要花费数原创 2021-04-22 13:31:15 · 88 阅读 · 0 评论 -
计算机系统基本概念笔记
计算机系统基本概念SMP与多核系统软件SMP与多核人们总是希望计算机越来越快,在过去的50年里,CPU的频率从几十kHz到现在的4GHz,整整提高了数十万倍,基本上每18个月频率就会翻倍,但是自2004年以后,这个规律似乎已经失效,CPU的频率自从那时开始再也没有发生质的提升,原因是人们在制造CPU的工艺方面已经达到了物理极限,除非CPU制造工艺有本质的突破,不然会一直被限制。在频率上短期内没有提高的余地了,于是人们开始想办法从另外一个角度来提高CPU的速度,就是增加CPU的数量,一个计算机拥有多个C原创 2021-04-20 16:53:01 · 103 阅读 · 0 评论