相信绝大多数程序员都有着和我相似的经历:在大一的时候,在一门或者叫做《程序设计基础》或者叫做《C语言》的课程里,写下了人生第一个程序,然后点击着VC6那个经典的运行键,看到屏幕上打出了一行“Hello World”。那个时候并不会想太多,总觉得写好代码,按下运行键,看着屏幕弹出的cmd窗口打印着我写下的逻辑,这一切似乎都是那么理所当然。
后来学习了更多知识,知道了计算机体系结构,知道了操作系统,知道了编译原理,知道了我们的C代码是依靠编译器编译成了二进制的机器码,才能再计算机中运行。可是似乎这些都是懵懵懂懂的概念,反而很多真真切切确实存在的问题,却是一直困扰着我的,即使是后来接触过驱动开发,自己写过makefile,我也是只对这些过程知其大概,比如:
(1)为什么我调用printf(), 调用fork()的时候,我只需要#include stdio.h和stdlib.h就可以使用这个函数呢,这个函数是谁实现的呢?实现的代码又在哪里呢?计算机怎么知道这些函数的处理逻辑呢?
(2)当程序由很多的C文件组成的时候,A.c想使用B.c的函数m时,只需要extern m,就可以调用该函数了。那么计算机是怎么准确找到这个名叫m的函数在b.c中的实现的呢?
(3)我们知道我们的程序在构建过程中,.c文件会被编译成.o文件,在一起组成.dl或者.img文件,那么.o文件到底是什么呢?
(4)windows中的静态库.lib和动态库.dll,linux中的静态库.a和动态库.so,这些所谓的库文件到底是啥?动态库和静态库又有什么区别?
直到一个偶然的机会,我读到了那本著名的《程序员的自我修养》,这本书令我豁然开朗,感获颇多。后来工作的时候,我从事的是底层软件开发的开发工作。我想如果不是对程序的编译链接装载有一个清晰的认识的话,我对工作的上手时间可能就没有这么快速了。
我认为,如果一个从事底层软件开发的程序员,对程序的编译,链接,装载过程认识不足的话,那么他便无法清楚的意识到到自己写下的代码在计算机中真正运行的情况,这对底层软件开发来说,将是十分严重的一个缺陷。因此,我想在这一系列的博文中,讲讲我对程序的链接装载的理解,因为编译本身是一个十分庞大而又复杂的过程,所以编译本身我并不会花费太多篇幅去讲,而且更重要的原因是,我也不懂啊(~ ̄▽ ̄)~
如果你对这些问题和当初的我一样,都是懵懵懂懂一知半解的状态,那么相信我,这个系列的博文将非常适合你。也十分推荐《程序员的自我修养》给你,这是一本让我受益匪浅的书籍,希望同样能帮助到您。