程序员的自我修养(笔记)

这本书对理解编程系统底层和在具体编程中解决问题的思路很有帮助,当然对自己的帮助不仅仅这些。现在常用的web编程框架和底层例如虚拟空间的设计其实是共通的,所以对web开发或者流行的各个框架的迅速应用也是非常有益的。看完第一章的介绍觉得非常好,接着阅读:

第二部分:静态链接

Chapter 2:编译和链接

2.1被隐藏了的过程

针对hello.c程序在linux下用gcc编译链接的过程如下图:



 该节对程序运行的预处理、编译、汇编和链接过程所做的具体工作进行了详细描述。

扫描二维码关注公众号,回复: 1336119 查看本文章

2.2编译器

主要通过一个实际例子完成词法分析、语义分析、代码优化、代码生成以及目标代码优化的讲解。

2.* 链接

运行时库:支持程序运行的基本函数的集合,例如下图中的crt1.o目标文件,所以库其实是一组目标文件的包




 Chapter 3:目标文件里面有什么

目标文件从结构上讲,它是已经编译后的可执行文件格式,只是还没有经过链接的过程,其中可能有些符号或有些地址还没有被调整。

3.1 目标文件的格式

PC平台流行的可执行文件格式主要是windows下的PE(Portable Executable)和Linux下的ELF(Executable Linkable Format),它们都是COFF(common file format)格式的变种。

不光是可执行文件按照可执行文件存储。动态链接库(DLL,Dynamic Linking Librar)(windows的.dll和Linux的.so)及静态链接库(Static Linking Library)(windows的.lib和linux的.a)文件都按照可执行文件格式存储。

3.2 目标文件是什么样的

下图是一段程序和生成的目标文件对应的存放位置



 总的来说,程序源代码被编译以后主要分成两种段:程序指令和程序数据。代码段属于程序指令,而数据段和.bss段属于程序数据。

Chaper 4: 静态链接

4.2.3 符号解析

我们编写程序时经常会出现“链接时符号未定义”。导致这个问题的原因很多,做常见的一般都是链接时缺少了某个库,或者输入目标文件路径不正确或者符号的声明与定义不一样。 所以从普通程序员的角度看,符号的解析占据了链接过程的主要内容。

Chapter 5 windows PE/COFF

COFF和Linux下的ELF结构非常类似,都是基于段的结构的二进制文件格式。PE是基于COFF的扩展,它比COFF文件多了几个结构。Windows下的可执行文件、动态链接库等都是用PE文件格式。

Chapter 7 动态链接

静态链接主要有两个方面的问题:

第一个是空间浪费的问题,每个程序都会保留大量的库函数和辅助数据结构,当运行的程序数量可观的时候,会造成大量的空间浪费。例如linux系统中,C语言程序用到的静态库在至少在1MB以上,如果机器中运行的程序有100个以上,就要浪费100MB的内存,如果磁盘中有2000个这样的程序,就要浪费2GB的磁盘空间。很多Linux机器中,/usr/bin中就有数千个可执行文件。

第二个问题是静态链接对程序的更新、部署和发布带来很多麻烦。例如某个第三方厂商开发的库,即使只做了很小的变动,利用到该库的厂商都需要重新链接,将新的版本提供给用户,会带来很大的不便。

解决办法就是将程序的各个模块分割,不再静态地链接在一起,而是在程序要运行时才进行链接。也就是将链接过程推迟到运行时再进行,这就是动态链接(Dynamic Linking)的思想。

动态链接也有诸多的问题。由于新的模块和旧的模块接口不兼容,可能导致新的程序安装完成之后其他程序无法正常工作的现象。

动态链接的基本实现:

Linux中,ELF动态链接文件被称为动态共享对象(Dynamic shared objects),简称共享对象,是以”.so“为扩展名的文件。

Windows系统中,动态链接文件称为动态链接库(Dynamic linking library),即经常见到的以".dll"为扩展名的文件。

动态链接的步骤和实现:

基本上分为三步,首先启动动态链接器本身;然后装载所有需要的共享对象;最后是重定位和初始化。

Chapter 8 Linux 共享库的组织

包括linux在内的开源操作系统都遵守一个叫做FHS(file Hierarchy Standard)的标准,这个标准规定了一个系统中的系统文件应该如何存放,包括各个目录的结构、组织和作用,有利于促进各个开源操作系统之间的兼容性。FHS规定,一个系统中主要有两个存放共享库的位置,它们分别如下:

/lib,这个位置主要存放系统最关键和基础的共享库,必然动态链接库、C语言运行库、数学库等,这些库主要是那些/bin 和/sbin下的程序所需要用到的库,还有系统启动时需要的库。

/usr/lib,这个目录下主要保存的是一些非系统运行时所需要的关键性的共享库,主要是一些开发时用到的共享库,也包含了开发时可能会用到的静态库、目标文件等。

/usr/local/lib,这个目录放置一些跟操作系统本身并不十分相关的库,主要是一些第三方应用程序的库。比如在系统中安装了python语言的解释器,那么与它相关的共享库可能会被放到/usr/local/lib/python,可执行文件可能被放到/usr/local/bin下。

共享库的创建也非常简单,在利用GCC时加上相应的参数即可。

第四部分:库与运行库

Chapter 10 内存

linux中将1G高地址空间给内核(0xffffffff-0xc0000000),windows将2G高地址空间给内核(0xffffffff-0x800000000),linux具体的内存地址分配如下图:

glibc中的malloc这样处理用户空间的请求:对于小于128KB的请求,它会在现有的堆空间里面,按照堆分配算法为它分配一段空间并返回;对于大于128KB的请求来说,它会使用mmap()函数为它分配一块匿名空间,然后再这个匿名空间中为用户分配空间。

堆的分配算法主要有三种:空闲链表、位图和对象池。

实际上很多现实应用中,堆的分配算法往往是采取多种算法复合而成的。比如对于glibc来说,它对于小于64字节的空间申请是采用类似于对象池的方法;而对于大于512字节的空间申请采用的是最佳适配算法;对于大于64字节而小于512字节的,它会根据情况采取上述方法中的最佳折中策略;对于大于128KB的申请,它会使用mmap机制直接向操作系统申请空间。

Chapter 11 运行库

11.2.1 C语言运行库

任何一个C程序,它的背后都有一套庞大的代码来进行支撑,以使得改程序能够正常运行。这套代码至少包括入口函数,及其所以来的函数所构成的函数集合。当然它还理应包括各种标准库函数的实现。这样的一个代码集合称之为运行时库(runtime library)。 而C语言的运行库,即被称为C运行库(CRT)。

一个C语言运行库大致包括如下功能:

1,启动与退出:包括入口函数和入口函数所依赖的函数;

2,标准函数:由C语言标准规定的C语言标准库中的函数实现;

3,I/O:I/O功能的封装和实现;

4,堆:堆的封装和实现;

5,语言实现:语言中一些特殊功能的实现;

6,调试:实现调试功能的代码。

glibc:linux平台下的C标准库

猜你喜欢

转载自backsnow.iteye.com/blog/1184330