Hello World历程

    Hello World,很简单的一句话,很多程序员入门新语言的第一行代码,能输出这句话在屏幕,说明整个开发环境都已经搭建好了,可以进一步开发了,如果连这句话都无法输出,后面做再多算法设计也没用,因为,你的软件无法在客户机使用,那么,计算机在输出Hello World的背后做了什么呢,下面记录一下。

    且看最简单的C++代码:

    

    在Linux下使用G++编译器编译运用如下:

    

    在生成可执行文件a.out背后,经历了如下几个过程:

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

    A. 预处理

    主要处理源码文件中以"#"符号开头的预编译指令,如“#include”、"#define"等。预处理过程中,大致做了如下几件事情:

    1. 展开宏定义

    2. 处理条件预编译指令,如"#if"

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

    3. 处理文件包含预编译指令

    4. 删除所有注释

    5. 添加行号和文件名标识,便于编译时编译器产生调试需要用到的符号信息

    6. 保留#pragma编译指令,该指令主要编译器会用到

    预编译如下:

    

    -E参数是进行预编译,生成的文件的扩展名为*.i 。调试时,如果觉得宏定义或文件保护不对,可以看看这么预编译文件是否正确。

    B. 编译

    在预处理的基础上,对预处理生成的文件进行词法分析、语法及语义分析及优化,产生汇编代码文件。如下:

    

    -S参数是进行编译

    C. 汇编

    对编译生成的汇编代码文件进行翻译生成机器码文件。如下:

    

    -c参数是进行汇编也可以一步到位:g++ -c main.cpp -o main.o

    可以用命令"objdump -s -d main.o"来看它的格式,如下(objdump属于binutils工具集的其中一个工具):

    

    可以看到,目标文件按段来存储的,如一般编译后的执行语存放在.text段,已初始化的全局变量和局部静态变量存放在.data段,未初始化的全局变量和局部静态变量存放在.bss段(用于定义符号并且为符号预留给定数量的未初始化空间)。上面输出信息比较详细,如果需要总览每个段的信息,使用"-h"参数即可:

    

    这里可以看到目标文件格式通用的格式,包含拥有的数据段及其权限、作用(.note.GNU-stack为堆栈提示段, CONTENTS:表示该段在文件中存在)。

    D. 链接

    前面只是针对一个文件生成目标机器码文件,要运行起来,还需要很多其他依赖的目标文件,类似与操作系统启动,操作系统是安装在硬盘的,直接启动是不行的,需要配合硬盘BIOS的那512字节,逐段加载到内存,经历一系列初始化,最终进入保护模式等,同样,要启动应用软件a.out,也是需要很多依赖,拼装成一个可执行软件,才可以运行。   

    链接过程主要有包括了地址和控件分配、符号决议和重定位等。        

    g++ main.o -o  main

    可以用ldd命令看其具体的依赖库:

    


猜你喜欢

转载自blog.csdn.net/linjingke32/article/details/80305049