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

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. JS - Object and Property的删除用法

    在JS中,Object和Property的删除用法: var myObject = {name:'jimmy', age:12, height:123} delete myObject["j ...

  2. saiku之行速度优化(三)

    经历了前两轮优化之后,saiku由不可使用,优化到可以使用,不过在分析大量日志数据的时候,还有顿卡的感觉!继续观察背后执行的Sql,决定将注意力关注到索引上面! 日志的主要使用场景是:固定日期维度的数 ...

  3. ORACLE自定义顺序排序-转

    ORACLE可以借助DECODE函数,自定义顺序排序: select * from ( select 'Nick' as item from dual union all select 'Viki' ...

  4. sizeof and strlen整理

    sizeof 定义 计算对象或类型所占用的字节数(byte) 记住是字节数,而不是个数 语法 sizeof(对象) int i; sizeof(i); sizeof(类型) sizeof(int); ...

  5. SGU 422 Fast Typing(概率DP)

    题目大意 某人在打字机上打一个字符串,给出了他打每个字符出错的概率 q[i]. 打一个字符需要单位1的时间,删除一个字符也需要单位1的时间.在任意时刻,他可以花 t 的时间检查整个打出来的字符串,并且 ...

  6. ios 同步Get请求的实现

    //第一步,创建URL NSURL *url = [NSURL URLWithString:@"http://itunes.apple.com/search?term=微信&enti ...

  7. mount分区为读写属性

    对于只读文件系统, 如果想要挂载为可读写的, 需要重新mount下, 如将config分区mount为读写的分区: mount -o remount,rw /config

  8. 【目录】C#操作Excel组件Spire.XLS系列文章目录

    本博客所有文章分类的总目录链接:http://www.cnblogs.com/asxinyu/p/4288836.html 1.C#操作Excel组件Spire.XLS文章目录 1.[原创].NET读 ...

  9. JavaScript的深拷贝的实现

    JavaScript的数据类型 简单数据类型 string number boolean function null undefined 复杂数据类型 String Number Boolean Fu ...

  10. 前端优化:RequireJS Optimizer 的使用和配置方法

    RequireJS Optimizer 是 RequireJS 自带的前端优化工具,可以对 RequireJS 项目中的 JavaScript & CSS 代码使用 UglifyJS 或者 C ...