本篇文章全部摘抄自学长博客供以后学习:

http://efraim.me/2015/12/05/tech-linux-2015-12-05/

排版因与博客园编辑器不同而稍作修改。

输出hello world!系统发生了什么?

经典的hello world!

 #include <stdio.h>

 int main ()
{
printf("hello world!");
}

该段程序,在hello world过程中,系统发生了什么?

0X00 新建hello.c

hello.c文件,是文件由0/1的位(bit)序列,8位组成一组,称为字节,一个个字节表示文件中的一个个字符。

由此引出,系统中的所有信息(磁盘文件,系统程序,网络传输的数据等等),都是一些0/1序列,当我们打开hello.c文件时,系统会按某种规则文件进行解析,最后呈现出人类能看懂的字符,而不是二进制0/1。

区分不同数据对象的唯一方法,就是系统读取这个文件时上下文(可以理解为当时的环境),比如,在不同的上下文中,一个同样的字节序列,有可能表示一个整数,浮点数,字符数或者机器指令。

0x01 解析hello.c

C语言是高级语言,所以这个形式的代码能让人读懂。但系统不认识,为了让系统能认识,需要将hello.c转化成一系机器能认识的语言指令,然后将这些指令按照一种称为可执行目标程序的格式进行打包,并以二进制磁盘文件形式存放,目标程序也可以称为可执行文件。

这里,我用GCC编译器,编译解析hello.c

  • 预处理阶段:-E

预处理器(cpp)主要处理根据以字符#开头的命令,修改原始的C程序。比如hello.c中第一行的#include <stdio.h> 命令会告诉预处理其读区系统头文件stdio.h的内容.并把它直接插入到程序文本中。此过程,会得到以.i作为扩展名。

`$ gcc -E hello.c -o hello.i`//预编译hello.c文件 输出hello.i文件

hello.i文件内容都有些什么呢?

 //hello.i
# "hello.c"
# "<built-in>"
# "<built-in>"
# "<built-in>"
# "<command line>"
# "<built-in>"
# "hello.c"
# "/usr/include/stdio.h"
# "/usr/include/stdio.h"
# "/usr/include/sys/cdefs.h"
# "/usr/include/sys/cdefs.h"
# "/usr/include/sys/_symbol_aliasing.h"
# "/usr/include/sys/cdefs.h"
# "/usr/include/sys/cdefs.h"
# "/usr/include/sys/_posix_availability.h"
# "/usr/include/sys/cdefs.h"
# "/usr/include/stdio.h"
# "/usr/include/Availability.h"
# "/usr/include/Availability.h"
# "/usr/include/AvailabilityInternal.h"
# "/usr/include/Availability.h"
# "/usr/include/stdio.h"
# "/usr/include/_types.h"
# "/usr/include/_types.h"
# "/usr/include/sys/_types.h"
# "/usr/include/sys/_types.h"
# "/usr/include/machine/_types.h"
# "/usr/include/machine/_types.h"
# "/usr/include/i386/_types.h"
# "/usr/include/i386/_types.h"
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef short __int16_t;
typedef unsigned short __uint16_t;
typedef int __int32_t;
typedef unsigned int __uint32_t;
typedef long long __int64_t;
typedef unsigned long long __uint64_t;
typedef long __darwin_intptr_t;
typedef unsigned int __darwin_natural_t;
# "/usr/include/i386/_types.h"
typedef int __darwin_ct_rune_t;
  • 编译阶段:-S

编译器(ccl)将hello.i翻译成文件文件hello.s文件,它包含一个汇编语言程序,汇编程序中的每条语句都以一种标准的文本格式确切地描述了一条条低级机器语言指令.所以该过程会检查代码规范,语法,词法分析,具体如下图.只有编译成功之后,才能生成具体的汇编代码。

$ gcc -S hello.i -o hello.s
 //hello.s
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min ,
.globl _main
.align , 0x90
_main: ## @main
.cfi_startproc
## BB#:
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset
Ltmp1:
.cfi_offset %rbp, -
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
subq $, %rsp
leaq L_.str(%rip), %rdi
movl $, -(%rbp)
movb $, %al
callq _printf
xorl %ecx, %ecx
movl %eax, -(%rbp) ## -byte Spill
movl %ecx, %eax
addq $, %rsp
popq %rbp
retq
.cfi_endproc .section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "hello world!"
.subsections_via_symbols
  • 汇编阶段:-c

汇编器(as)将hello.s 文件翻译成机器语言指令,,把这些指令打包成一种叫做可重定向目标程序的格式,并且保存在hello.o文件中.该文件是一个二进制文件,他的字节编码是机器语言指令而不是字符,如果用编辑器打开将是一段乱码。

  • 链接阶段:

注意,hello程序调用了printf函数,他是每个C编译器都会提供的标准C库的一个函数.该函数存在于一个名为printf.o的单独的预编译好的文件中,必须将该文件以某种方式合并到我们的hello.o的文件中。连接器(ld),就复制处理这种合并。结果就得到一个hello文件,是一个可执行文件。

「C语言」C输出hello world!系统发生了什么?的更多相关文章

  1. 「C语言」文件的概念与简单数据流的读写函数

    写完「C语言」单链表/双向链表的建立/遍历/插入/删除 后,如何将内存中的链表信息及时的保存到文件中,又能够及时的从文件中读取出来进行处理,便需要用到”文件“的相关知识点进行文件的输入.输出. 其实, ...

  2. 「C语言」Windows+EclipseCDT下的C语言开发环境准备

    之前写过一篇 「C语言」在Windows平台搭建C语言开发环境的多种方式 ,讨论了如何在Windows下用DEV C++.EclipseCDT.VisualStudio.Sublime Test.Cl ...

  3. 「C语言」常量和变量的表示、应用和变量命名规则

    在程序运行中,其值不能改变的量成为常量. 在基本数据类型中,常量可分为整型常量.实型常量.符号常量和字符型常量(包括字符常量和字符串常量),现分别介绍如下: 目录: 一.常量 二.C语言标识符 三.变 ...

  4. 「C语言」原码反码补码与位运算

    尽管能查到各种文献,亲自归纳出自己的体系还是更能加深对该知识的理解.     本篇文章便是在结合百度百科有关原码.反码.补码和位运算的介绍并深度借鉴了张子秋和Liquor相关文章后整理而出.   目录 ...

  5. 「C语言」单链表/双向链表的建立/遍历/插入/删除

    最近临近期末的C语言课程设计比平时练习作业一下难了不止一个档次,第一次接触到了C语言的框架开发,了解了View(界面层).Service(业务逻辑层).Persistence(持久化层)的分离和耦合, ...

  6. 「C语言」int main还是void main?

    从大一入学刚接触C到现在已满7个月了,虽然刚开始就知道```int main```才是标准的写法,但一直没有深刻理解为什么不能用```void main```而必须使用```int main```. ...

  7. 「C语言」在Windows平台搭建C语言开发环境的多种方式

    新接触C语言,如何在Windows下进行C语言开发环境的搭建值得思考并整理. 以下多种开发方式择一即可(DEV C++无须环境准备). 注:本文知识来源于  Windows 平台搭建C语言集成开发环境 ...

  8. 「C语言」数据类型及混合运算与类型转换

    深入学习C语言时,有必要先了解一下数据类型的概念,以及它们之间的混合运算与类型转换. 本篇文章便是根据<C语言程序设计教程>和在线翻阅资料后整理而出.(练习题将逐步更新) 目录:     ...

  9. 「专题总结」LCT 2

    差不多理解板子之后,写了一些奇怪的题. 但是还是那个问题:树剖真好使. 魔法森林:mikufun说这个是傻逼题. 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐士. 魔法森林可以 ...

随机推荐

  1. Spark源码系列(八)Spark Streaming实例分析

    这一章要讲Spark Streaming,讲之前首先回顾下它的用法,具体用法请参照<Spark Streaming编程指南>. Example代码分析 val ssc = )); // 获 ...

  2. Selenium关键字驱动测试框架Demo(Java版)

    Selenium关键字驱动测试框架Demo(Java版)http://www.docin.com/p-803493675.html

  3. 彻底删除mysql方法

    首先,先在服务(开始——>控制面板——>管理工具——>服务)里停掉MySQL的服务.打开控制面板-添加删除程序,找到MySQL,卸载.或者用360安全卫士来卸载也行.也可以用mysq ...

  4. C#连接mysql数据库插入数据后获取自增长主键ID值

    From: http://blog.csdn.net/zbc496218/article/details/51082983 MySqlConnection conn = new MySqlConnec ...

  5. 未知高度定宽div水平居中及垂直居中(兼容ie6及其他牛逼浏览器)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  6. jQuery浏览器差异

    //firefox Interface.send(data,function(msg){ $(msg).find("CARINFO").each(function(i){ var ...

  7. MyBatis知多少(12)私有数据库

    如果你从事软件开发工作有了一段时间的话,那么肯定听过关于“自己动手还是花钱购买” 的争论.该争论是说,针对一个业务问题,我们是应该自己动手构建自己的解决方案呢,还是应 该花钱购买一个声称已经解决了此问 ...

  8. codeforces C. Diverse Permutation(构造)

    题意:1...n 的全排列中 p1, p2, p3....pn中,找到至少有k个 |p1-p2| , |p2-p3|, ...|pn-1 - pn| 互不相同的元素! 思路: 保证相邻的两个数的差值的 ...

  9. 《编写高质量代码:改善C#程序的157个建议》源码下载

    ==== 目录 前 言第一部分 语言篇第1章 基本语言要素 / 2建议1:正确操作字符串 / 2建议2:使用默认转型方法 / 6建议3:区别对待强制转型与as和is / 9建议4:TryParse比P ...

  10. 剑指架构师系列-Struts2的缓存

    Struts2的缓存中最重要的两个类就是ReferenceMap与ReferenceCache.下面来解释下ReferenceCache中的get()方法. public V get(final Ob ...