可执行文件格式详述,ABI和loader……

阅读更多
上回书说到可执行文件的格式,这一节详细描述一下。
可执行文件是由头和体组成的。这跟别的复杂一点的文件一样。它的体分成一些叫做节(section)的东西,这是它的特色。另外比较有特色的东西是:我们一般把可执行文件叫做程序的影像(image)。唔,这个叫法也不赖。可执行文件的价值在于执行,执行的程序也就是活着的程序叫做程序的影像。呵呵,这个概念打通了文件和进程的通道,以前说过的loader。一般情况下,可执行文件放在永久性的存储设备上,进程放在速度较快的主存上——一般是半导体存储设备,易失性的。loader干的主要的活之一就是把可执行文件从速度较慢的哟耐久性存储设备转移到速度较快的主存上。这个转移有什么难处呢?有一定的难点。最主要的就是:由于程序被转移(又叫做装载)到主存的以后,这个程序就要运行了,照常理想来,一个程序要施展其手脚,总得先准备出场地。是的,要准备其场地的。可以想象的到,其中最主要的是要操作的数据。但是别忘了,数据难道不包括在可执行文件影像里面?确实,有一种数据不包括在里面。就是那种没有初始值的数据。没有初始值的数据,包括在image里面也是没有价值的,是吧。所以,需要在主存中开辟这么一块地方,用来存放这种数据。是不是这就完了?不是,参见我写的关于对象生命周期和内存模型的概念就知道,我们还要准备好栈空间,以供程序运行的时候使用,准备好堆空间,以供程序运行的时候使用。是不是就完了?不是,还不是,还有别的。

有一个叫做重定位的概念需要在这儿引入。程序中需要操作数据,这个大家都知道,但是怎么用来指定那个数据呢?比如:程序中说,要把a和b相加的和赋值给c,怎么表达呢?用a b c对象的名字来表达?不是。呵呵,用的是a b c对象的地址。地址!这是一个关键的概念。好,我们现在看看会导致什么问题。c = a + b会演化成,load data from address of a,load data from address of b,add these data,store the result to address of c。我们不关心别的,就关注:address of {a|b|c},它们怎么来的,我们在程序中可没有给它们地址啊。呵呵,肯定是中间某个环节给出来的了。我们看看有可能是那个环节。compiler?嗯,很有可能,compiler给出各个对象一个唯一的地址。linker,对,linker给它们分配地址也很正常。那loader呢?loader给出地址也很合理。其实,这些环节都曾经给出了这些对象的地址。是的,都给出过。这里面会涉及到一个相对地址和绝对地址的问题。绝对地址就是指在运行环境中给准备的地址空间中指定其一。比如:运行环境给准备了4G的地址空间,你说你的某个对象使用3038M139K那个地方的空间。这就是绝对地址。绝对地址不好。原因很简单。你得自己保证对象的地址不冲突,而且,强迫你依赖于运行环境。那么相对地址呢?嗯,它在linker的运作下基本上是一个基本要求。 compiler生成相对地址,linker把它们(模块们)联合起来,放入同一个地址空间中,loader把image装入主存时,很有可能重新定位 image中各个对象的地址。

好的。重定位解释完了。是不是loader的活也干完了呢?哦,no,还有点。这牵扯到外部对象引用的问题。想一想,对连接器面对的各个模块来说,别的模块中的对象也算是外部对象。所以,外部对象的引用问题也不是很难,当然,也不很简单。

好了,说了这些东西以后,我们的可执行文件究竟以什么格式存在呢?且看……

你可能感兴趣的:(C,C++,C#)