Hello World之编译链接装载与执行(1)
一:前言
我打算写一系列博客来说说我对Hello World
在计算机中的生命旅程的理解,我是一名软件工程专业的大三学生,有关这个问题我主要的参考书有《深入理解计算机系统》、《现代操作系统》、《程序员的自我修养》,除了这些,我还参考了一些大牛的博客,如果后面需要,我会贴出来,我还在我的Centos 7
系统上做了一些验证。如果上面的三本书你都看过,并且看的还算认真,能回答这个问题 https://www.zhihu.com/question/53042020
(问:下面的程序需要经过链接吗?)
//1.c
-------------------------
int main()
{
return 0;
}
那我觉得你可以关掉我的博客去冲杯咖啡歇歇了。如果不能回答,并且想知道答案,那我们一步一步往下走,因为我要从头说起,所以可能废话会有点多。
但是你要是想急切知道我对这个问题的看法,请点击: [尚未完成]
好了,我们还是一步步往下走吧~
二:GCC 是什么?
回答:
1、是c
语言的编译器。(单纯、你不知道它还能编译其它语言吗?)
2、是GNU
的编译器套件,可以编译多种语言。(司机,看来你基础不错)
3、是GUN编译系统
的编译驱动程序。(我的天,老司机阿)
那为什么说GCC
是GUN编译系统
的编译驱动程序呢?我们继续。
三:Hello World 诞生啦!
//Hello.c
----------------------------
#include<stdio.h>
int main(int argc,char *argv[])
{
printf("Hello World\n");
return 0;
}
上面的是源程序,如果想得到可运行的目标文件:
已经OK了。但是我们才不会这样呢?这个几乎瞬间完成的动作,其实是由这么几个步骤组成的。
预处理 -> 编译 -> 汇编 -> 链接 -> 装载
下面我们来依次说每个步骤。
四:预处理
1、使用GCC -E
参数完成。
预处理会干什么事情:
- 展开所有的宏定义并删除 #define
- 处理所有的条件编译指令,例如 #if #else #endif #ifndef …
- 把所有的 #include 替换为头文件实际内容,递归进行
- 把所有的注释 // 和 / / 替换为空格
- 添加行号和文件名标识以供编译器使用
- 保留所有的 #pragma 指令,因为编译器要使用
- ……
处理完成之后看看我们的Hello.i
,发现原来8
行代码现在变成了接近700
行,因为将<stdio.h>
的文件被替换进来了,在最后几行找到了我们自己Hello.c
的代码:
2、使用系统默认的预处理器cpp
完成。
预处理除了使用GCC -E
参数完成之外,我们还可以使用系统默认的预处理器cpp
完成。如下所示:
我们看看Hello.ii
的代码:
虽然Hello.i
和Hello.ii
的代码对应的行数不同,但是内容却是一模一样
的,只是中间空行的数量不同而已。
OK ,接下来,继续向编译出发。
五:编译
编译是将源文件
转换成汇编代码
的过程,具体的步骤主要有:
词法分析 -> 语法分析 -> 语义分析 -> 中间代码生成 -> 目标代码生成。
如果不想了解具体过程,跳过下面两行~
有关词法分析,我写过一个简单的词法分析器:[点击这里]
有关语法分析,针对LL1
分析法,我实现过一个简单的语法分析器:
http://blog.csdn.net/yangbodong22011/article/details/52951001
1、使用GCC -S
参数完成。
查看Hello.s
发现已经是汇编代码了。
2、使用系统默认的编译器cc1
完成这个过程。
前面的预处理命令cpp
可能大家的系统上都有,我们输入cp
,然后Tab
两下(Linux系统上表示提示补全命令),系统提示如下:
倒数第二个命令就是cpp
了。但是我们cc
同样的过程的时候却发现:
并没有cc1
这个命令,但是cc1
确实是Linux
系统上默认的编译器呀,我们在系统上找找看:
看上图第二条,/usr/libexec/gcc/x86_64-redhat-linux/4.8.2/cc1
,尝试着去看下:
有可执行权限,那为何不试试能不能用来编译Hello.ii
呢?
好像没有什么报错,迫不及待的看看Hello.ss
的内容:
发现和Hello.s
的是一样的。编译成功。Goto 汇编。
六:汇编
汇编是将汇编代码
生成机器代码
的过程。得到的文件叫可重定位的目标文件
,机器代码
是二进制代码
,并且根据不同的平台,生成二进制代码也不同。
1、使用GCC -c
参数完成。
其实也可以查看下Hello.o
的内容:
只是乱码罢了。要是想看,我们可以使用hexedit,readelf
和objdump
这三个工具。
hexedit
只是个将二进制文件用十六进制打开的工具,我们执行:
$ sudo yum install hexedit
$ hexedit Hello.o
可以看到:
最右边是源文件被翻译成可见字符,点.
表示的都是不可见字符。这样看当然没有多大实际意义,但是一些输出的字符串Hello World
,包括整个文件的类型ELF
都是可以看到的。
readelf
和objdump
我们后面再说。
2、使用系统默认的汇编器as
完成。
hexedit 看看 :
使用 cmp 命令比较Hello.oo
和Hello.o
只有极少数字符不同。可能也是格式问题。下面就要进入链接
这个阶段了,本篇博客就到这里吧。
总结:上面的过程中,我们已经将Hello.c
源程序经过预处理
,编译
,汇编
阶段变成了二进制代码,这三个过程我们都是用两种方法完成的,一种是GCC + 参数
的方法,另一种是使用系统默认的预处理器,编译器,汇编器
。但是这两种方法都达到了我们的目的,那有关本文第二部分的问题GCC是什么?
的答案,我之前之所以同意第三个答案:GCC是GUN编译系统的编译驱动程序
,就是因为GCC编译
的过程中,真正干活的还是我们系统默认的预处理器,编译器,汇编器
,如果你还是不信,GCC -v
显示过程看看不就好了:
我找点有用的:
这不是调用as
了吗。所以请接受我的观点。好了,时间也不早了,该问问大拿困了没,结束本文之前,我再问一个问题:
我们现在得到的
Hello.o
是可以运行的吗?给它加上x
权限试一试?
Hello World之编译链接装载与执行(1)的更多相关文章
- linux 编译,链接和加载
1. 序 最近在折腾各种.so,碰到了一些问题,一开始对于很多错误也没有头绪,茫然不知所措.索性化了一天多时间将<<程序员的自我修养—链接.装载与库>>中部分内容略读了一遍 ...
- 【C编程基础】C编译链接命令gccc
1.gcc安装 rpm -qa|grep gcc ==>检查gcc是否安装 gcc -v ==>检查gcc版本 yum -y install gcc ==>安装gcc 2.基本语法 ...
- Linux设备驱动程序学习----3.模块的编译和装载
模块的编译和装载 更多内容请参考Linux设备驱动程序学习----目录 1. 设置测试系统 第1步,要先从kernel.org的镜像网站上获取一个主线内核,并安装到自己的系统中,因为学习驱动程序的编写 ...
- 从四个问题透析Linux下C++编译&链接
摘要:编译&链接对C&C++程序员既熟悉又陌生,熟悉在于每份代码都要经历编译&链接过程,陌生在于大部分人并不会刻意关注编译&链接的原理.本文通过开发过程中碰到的四个典型 ...
- GCC编译器编译链接
在gcc编译器环境下,常见的文件扩展名的含义如下: .c:C源程序,经过预编译后的源程序也为.c文件,它可以通过-E参数输出. .h:头文件 .s:经过编译得到的汇编程序代码,它可以通过-S参数输出. ...
- C语言编译链接
转载请标明: 编译链接是使用高级语言编程所必须的操作,一个源程序只有经过编译.链接操作以后才可以变成计算机可以理解并执行的二进制可执行文件. 编译是指根据用户写的源程序代码,经过词法和语法分析,将高级 ...
- C++常见gcc编译链接错误解决方法
除非明确说明,本文内容仅针对x86/x86_64的Linux开发环境,有朋友说baidu不到,开个贴记录一下(加粗字体是关键词): 用“-Wl,-Bstatic”指定链接静态库,使用“-Wl,-Bdy ...
- c语言编译预处理和条件编译执行过程的理解
在C语言的程序中可包括各种以符号#开头的编译指令,这些指令称为预处理命令.预处理命令属于C语言编译器,而不是C语言的组成部分.通过预处理命令可扩展C语言程序设计的环境. 一.预处理的工作方式 1.1. ...
- 实现一个基于tcc/tlink的简单的编译链接工具
一.基础研究 在这里我们需要提供一套新的c语言开发工具cc,它支持的c程序不是从main开始运行而是从CMain开始运行. 书上已经对该工具程序进行了需求分析:(1)要在屏幕中间显示彩色的字符串:(2 ...
随机推荐
- 关于微信小程序爬虫关于token自动更新问题
现在很多的app都很喜欢在微信或者支付宝的小程序内做开发,毕竟比较方便.安全.有流量.不需要再次下载app,好多人会因为加入你让他下载app他会扭头就走不用你的app,毕竟做类似产品的不是你一家. 之 ...
- P6134-[JSOI2015]最小表示【bitset,拓扑排序】
正题 题目链接:https://www.luogu.com.cn/problem/P6134 题目大意 给出一张\(n\)个点\(m\)条边的\(DAG\).求联通情况不变的情况下最多删除几条边. \ ...
- 深入浅出WPF-09.Command(命令)
命令 1)命令系统的基本元素 命令(Command),WPF的命令实际上就是实现了ICommand接口的类,平时使用最多的是RoutedCommand类 命令源(Command Source),即命令 ...
- 解决导入MAVEN项目报错Dynamic Web Module 3.1 requires Java 1.7 or newer.
解释:web模块需要使用java1.7及以后的版本,目前的版本不符合.因而只需要修改java版本到1.7及以上即可. 解决方法: 1.保证 在eclipse 构建 web中关于java版本有三处需要修 ...
- APScheduler(python 定时任务框架)最简单使用教程
有时候需要部署一些很简单的python定时任务,使用APScheduler是很好的选择.只需要简单的设置几个参数,就可以实现定时.定分甚至秒来跑. 第一步:用pip安装APScheduler pip ...
- webpack基本用法及原理(10000+)
1 webpack是什么 所有工具的出现,都是为了解决特定的问题,那么前端熟悉的webpack是为了解决什么问题呢? 1.1 为什么会出现webpack js模块化: 浏览器认识的语言是HTML,CS ...
- react-native移动端设置android闪屏页
前言 因为app启动时会白屏一段时间,导致让人用起来非常的不舒服,后来了解一下知道这叫做闪屏 于是着手解决这个白屏的问题,换个颜色?不行,不如用一张好看的图片来替换,这样才让人看起来更加舒服. 那么该 ...
- python paramiko实现ssh上传下载执行命令
paramiko ssh上传下载执行命令 序言 最近项目经常需要动态在跳板机上登录服务器进行部署环境,且服务器比较多,每次完成所有服务器到环境部署执行耗费大量时间.为了解决这个问题,根据所学的执行实现 ...
- 遇到括号就是栈(bushi)
CF508E Arthur and Brackets 我在赛场上想都没想直接DP \(O(n^3)\)过了 但别人说正解是栈+贪心 讲讲DP \(bool\) \(dp[i][j]\)表示从第i对括号 ...
- 洛谷4051 JSOI2007 字符加密(SA)
真是一道良好的SA模板题 首先,由于涉及到从左边移动到右边这个过程,我们不妨直接把字符串复制一遍,接在后面. 然后直接构造后缀数组,按排名从小到大,枚举所有的位置,如果这个后缀的起始点是在原串中的,那 ...