Hu Zhenyu's Blog


访客计数:
net traffic statistics

about

《程序员的自我修养》小记

之前有一本书,一直想看完它,但是总是被各种各样的事情吸引了注意力。这个学期开学以来,前两周都挺空闲,平均每天才一节课,没事,我就又把这本书翻了出来。《程序员的自我修养——链接、装载和库》。这本书的主标题借用了那个著名的表演艺术家——斯坦尼斯拉夫斯基的著作《演员的自我修养》。

每一个初学编程的人可能都会好奇,为什么我们写出来的类似英语的语句能够变成计算机可以执行的二进制代码?计算机专业有一门专门讲述这个原理的课程《编译原理》,作为非计算机专业的人可能不会去啃那本有点晦涩难懂的教科书,不过我们还是可以基本的了解一下编译器工作的过程。

一般的C/C++语言或者是Pascal之类的编译型语言是这样生成可执行程序的:

1.首先,编译器会对源程序进行预处理。比如C语言的程序一般开始会有一些#include语句和一些宏定义,要把这些文件包含进来,并把所有的宏展开,把所有的注释去掉。
2.第二步是编译,编译器把经过预处理的文件进行词法分析,语法分析,语义分析和优化后就会生成相应的汇编代码。
3.第三步是汇编,汇编器将编译器生成的汇编代码一条一条的翻译成机器代码,生成目标文件(Windows下一般是.obj文件,linux下一般是.o文件)。
4.第四步,链接生成可执行文件。

上面生成的目标文件虽然已经是机器代码了,但是还不能直接执行,一般目标文件中包含的是你自己所写的代码的机器代码,但不包含你调用的各种库函数的代码,只有一些库函数的符号,不知道具体的函数的地址。链接就是把你调用的函数和你自己写的函数链接到一起,并设定好各个代码段在的位置,和各个函数的地址。**

如果,读者有汇编语言编程的经历,那应该知道一个程序会分成好几个代码段: .text 代码段 .data 数据段 .bss 未初始化的数据段

代码段里面存放的是可执行的机器指令,数据段存放的是初始化了的变量,bss存放的是未初始化的变量。还有一些其他的代码段,而且我们自己也可以定义某段数据存放在什么自定义的段里面。

链接的时候,就是要将不同的目标文件中的函数链接到链接脚本指定的可执行文件的段中。 不同目标文件如何知道各个函数或者是变量是同一个变量? 各个编译器在编译的时候都会给各个变量还有函数设定符号,如果是同样的符号就代表是同一个对象,链接的时候就会链接到同一个地址。

书中以一个“最小的hello world程序”简单介绍了一下链接脚本的语法。这个hello world我编译的结果是只有771字节。它完全没有使用标准I/O中的printf()函数,而是使用嵌入汇编。而且也没有main()函数,而是通过链接脚本指定了程序的入口为nomain()函数。 这个链接脚本如下:

ENTRY(nomain)
SECTIONS
{
   . = 0x08048000 + SIZEOF_HEADERS;
   tinytext : { *(.text) *(.data) *(.rodata) }
   /DISCARD/ : { *(.comment) }
}

第一行规定了这个程序的入口函数。

SECTIONS规定了从输入的目标文件的段怎么链接到输出的可执行文件的段。第一行设定当前虚拟地址为 0x08048000+SIZEOF_HEADERS;

第二行设定所有输入文件中的 .text .data .rodata段都合并输出为可执行文件的tinytext段。

第三行设定 不要输出 .comment段 ,这个段里面一般是一些注释。

如果读者对于程序是如何链接和在计算机中被执行的,可以好好去看看这本书。 还有几本书也是很好的:

*《深入理解计算机系统》这本英文缩写为CSAPP的书是詹姆斯卡梅隆大学计算机专业计算机导论的教材,很多人都推荐这本书。

*《Linker and Loader》这本书是链接和装载方面的最完整和权威的著作。

上一篇: MSP430单片机简介
下一篇: 使用jekyll静态生成器建立个人博客


知识共享许可协议

本站采用 知识共享署名-非商业性使用-相同方式共享3.0 中国大陆许可协议 进行许可,转载请注明出处。

推荐使用 chrome 浏览器浏览本站。