《程序员的自我修养》第二章学习笔记

第二章 编译和链接

2.1被隐藏了的过程

我们知道,一个程序由源代码到可执行文件往往由这几步构成:

预处理(Prepressing)-> 编译(Compilation)-> 汇编(Assembly)-> 链接(Linking)。

如图所示,

2.1.1预编译 

#include<stdio.h>

int main(void)
{
  printf("Hello World\n");
  return 0;          
}

    如上述文件hello.c,  gcc -E hello.c -o hello.i

    预编译过程主要处理哪些源代码文件中的以 "#" 开始的预编译指令,比如 #include,#define 等,主要处理规则如下:

  1. 将所有的#define删除,并且展开所有的宏定义。

  2. 处理所有的预编译指令,比如 "#if" "#ifdef" "#elif" "#else" "#endif"等。

  3. 处理"#include"预编译指令,将被包含的文件插入到该预编译的位置。注意:这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。

  4. 删除所有的注释 "//"  ''/* */"。

  5. 添加行号和文件名标识,比如#2"hello.c"2,以便于编译时编译器产生调试用的符号信息及用于编译时产生编译错误或警告时能够显示行号

  6. 保留所有的#pragma编译器指令,因为编译器需要用到它们。

  经过预编译后的.i文件不包含任何宏定义(所有的宏都展开了),被包含的文件也被插入到.i文件中。

  参考文献《程序员的自我修养--链接、装载与库》 P39

2.1.2编译 详情参考2.2

1,现在版本的GCC把预编译和编译合并成了一个步骤,使用一个叫做ccl的程序来完成这两个步骤。

2,gcc只是一些后台程序的包装,它会根据不同的参数要求去调用预编译程序ccl,汇编器as,链接器ld。

2.1.3汇编

1,汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。

2,所以汇编器的汇编过程相对于编译器来讲比较简单,它没有复杂的语法,也没有语义,也不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译就可以了。

3,经过预编译、编译和汇编直接输出目标文件(Object File)。

4,可调用汇编器as来完成,  as hello.s –o hello.o

5,或者 gcc –c hello.s –o hello.o

6,也可以一步到位  gcc –c hello.c –o hello.o

2.1.4链接

2.2编译器做了什么  参考如下

http://www.cnblogs.com/xcywt/p/4902789.html

2.3链接器的年龄比编译器长

2.4模块拼装---静态链接

  1,  人们把每个源代码模块独立编译,然后按照需要将它们“组装”起来,这个组装的过程就是链接(Linking)。

  2,  链接的主要内容就是:把各个模块之间相互引用的部分都处理好,使得各个模块之间能够正确的衔接。

  3,  从原理上说,链接器的工作无非就是把一些指令对其他符号地址的引用加以修正。

  4,  链接过程主要包括了:地址和空间分配(Address and Storage Allocation),符号决议(Symbol Resolution)和重定位(Relocation)。

  5,  最基本的静态链接如下图所示,源文件经过编译成目标文件(*.o /  *.obj),目标文件和库一起链接最终形成可执行文件。

  6,  假如main.c用到了另一个模块fun.c中的food()函数。

    (1)编译mian.c时并不知道foo()的地址,所以暂时把这些调用foo()的指令的目标地址搁置。

    (2)链接器会根据所引用的符号foo,自动去相应的fun.c模块查找foo的地址。

    (3)然后将main.c中所有用到foo的指令重新修正,让它们的目标地址为真正的foo函数的地址。

  7,  地址修正的过程也叫重定位(Relocation)。

  8,  每个要被修正的地方叫一个重定位入口(Relocation Entry)。

参考文献《程序员的自我修养--链接、装载与库》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码匠的流水账

nginx proxy cache配置参数解读

本文主要解析一下nginx ngx_http_proxy_module中的cache相关配置参数。

1211
来自专栏gaoqin31

PHP 输出控制

默认情况下,输出一个字符串到浏览器,经过3个阶段PHP buffer->Tcp buffer->浏览器(IE浏览器有的版本也存在buffer)

1634
来自专栏前端杂货铺

高吞吐koa日志中间件

Midlog中间件 node服务端开发中少不了日志打点,而在koa框架下的日志打点在多进程环境中日志信息往往无法对应上下文,而且在高并发下直接进行写buffer...

54010
来自专栏web编程技术分享

【Java框架型项目从入门到装逼】第五节 - 在Servlet中接收和返回数据

3387
来自专栏开源优测

工具篇 - JMeter组件手册04

前言 在jmeter中提供了一系列的不同的组件,每一种组件都提供了某类功能的实现,用于支持性能测试的实施。 请看下图,jmeter的核心组件构成。 ? 学习、研...

3588
来自专栏java达人

DWR简介

image.png DWR(Direct Web Remoting)是一个WEB远程调用框架.利用这个框架可以让AJAX开发变得很简单.利用DWR可以在客户...

20010
来自专栏Clive的技术分享

cgi、fastcgi及php-fpm分别是什么cgifastcgiphp-fpm

cgi cgi是通用网关接口定义。当web server收到/index.php这个请求后,会启动对应的CGI程序,这里就是PHP的解析器。接下来PHP解析器会...

2976
来自专栏崔庆才的专栏

利用 Flask+Redis 维护 IP 代理池

目前有很多网站提供免费代理,而且种类齐全,比如各个地区、各个匿名级别的都有,不过质量实在不敢恭维,毕竟都是免费公开的,可能一个代理无数个人在用也说不定。所以我们...

2.2K0
来自专栏racaljk

C++并发低级接口:std::thread和std::promise

相比std::async,std::thread就原始多了。thread一定会创建新线程(而不是像async那样创建的时候可能不会,后面才创建新线程(std::...

1884
来自专栏乐沙弥的世界

RAC 环境下的重要参数

    Oracle 数据库启动时会根据参数文件中提供的相关参数启动Oracle实例。这些参数包括数据库名字、sga,pga的分配,控制文件的位置,undo,p...

601

扫码关注云+社区