「C语言」C输出hello world!系统发生了什么?
本篇文章全部摘抄自学长博客供以后学习:
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!系统发生了什么?的更多相关文章
- 「C语言」文件的概念与简单数据流的读写函数
写完「C语言」单链表/双向链表的建立/遍历/插入/删除 后,如何将内存中的链表信息及时的保存到文件中,又能够及时的从文件中读取出来进行处理,便需要用到”文件“的相关知识点进行文件的输入.输出. 其实, ...
- 「C语言」Windows+EclipseCDT下的C语言开发环境准备
之前写过一篇 「C语言」在Windows平台搭建C语言开发环境的多种方式 ,讨论了如何在Windows下用DEV C++.EclipseCDT.VisualStudio.Sublime Test.Cl ...
- 「C语言」常量和变量的表示、应用和变量命名规则
在程序运行中,其值不能改变的量成为常量. 在基本数据类型中,常量可分为整型常量.实型常量.符号常量和字符型常量(包括字符常量和字符串常量),现分别介绍如下: 目录: 一.常量 二.C语言标识符 三.变 ...
- 「C语言」原码反码补码与位运算
尽管能查到各种文献,亲自归纳出自己的体系还是更能加深对该知识的理解. 本篇文章便是在结合百度百科有关原码.反码.补码和位运算的介绍并深度借鉴了张子秋和Liquor相关文章后整理而出. 目录 ...
- 「C语言」单链表/双向链表的建立/遍历/插入/删除
最近临近期末的C语言课程设计比平时练习作业一下难了不止一个档次,第一次接触到了C语言的框架开发,了解了View(界面层).Service(业务逻辑层).Persistence(持久化层)的分离和耦合, ...
- 「C语言」int main还是void main?
从大一入学刚接触C到现在已满7个月了,虽然刚开始就知道```int main```才是标准的写法,但一直没有深刻理解为什么不能用```void main```而必须使用```int main```. ...
- 「C语言」在Windows平台搭建C语言开发环境的多种方式
新接触C语言,如何在Windows下进行C语言开发环境的搭建值得思考并整理. 以下多种开发方式择一即可(DEV C++无须环境准备). 注:本文知识来源于 Windows 平台搭建C语言集成开发环境 ...
- 「C语言」数据类型及混合运算与类型转换
深入学习C语言时,有必要先了解一下数据类型的概念,以及它们之间的混合运算与类型转换. 本篇文章便是根据<C语言程序设计教程>和在线翻阅资料后整理而出.(练习题将逐步更新) 目录: ...
- 「专题总结」LCT 2
差不多理解板子之后,写了一些奇怪的题. 但是还是那个问题:树剖真好使. 魔法森林:mikufun说这个是傻逼题. 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐士. 魔法森林可以 ...
随机推荐
- 使用Aspose.Cells 设置chart的y坐标轴显示值
目的:设置chart的y坐标轴显示值 用aspose.cell生成的chart生成的Y轴是默认生成的,自己要定义y轴坐标值1.把数据源写到excel里面,list里面2.y轴坐标自己定义 第一种:默认 ...
- Spring Boot 之 HelloWorld详解
摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! “以前是人放狗看家,现在是狗牵着人散步” — 随笔 一.Spring Boot 自述 世界上最好 ...
- C8051 SMBus 原理
一.SMBus总线 SMBus串行I/O接口完全符合系统管理总线规范 1.1 版.它是一个双线的双向串行总线,与I2C串行总线兼容.系统控制器对总线的读写操作都是以字节为单位的,由SMBus接口自 ...
- 彻底解决Google浏览器CSS居中问题
div做的界面时,又出现CSS hack(CSS兼容浏览器问题)在IE内核浏览器或者firefox浏览器中都能居中,没有居中的可以用其特殊标签来设定居中,如下划线 _ IE6优先识别,!importa ...
- wireshark解密本地https流量笔记
此方式支持firefox,chrome 建立path变量 SSLKEYLOGFILE=c:\ssl.key 重启firefox chrome,访问https网站会自动生成ssl session key ...
- Some User Can Not Execute "Ship Confirm"(Doc ID 473312.1)
APPLIES TO: Oracle Shipping Execution - Version 11.5.10.2 and later Information in this document app ...
- centos 7 卸载 mariadb 的正确命令
#列出所有被安装的rpm package rpm -qa | grep mariadb #卸载 rpm -e mariadb-libs-5.5.37-1.el7_0.x86_64 错误:依赖检测失败: ...
- react-native SyntaxError xxxxx/xx.js:Unexpected token (23:24)
在运行react-native项目时提示 SyntaxError xxxxx/xx.js:Unexpected token (23:24) 我这边的问题原因:jsx语法错误,解决办法就是认真排查代码然 ...
- Base64 算法原理,以及编码、解码【加密、解密】 介绍
Base64编码,是我们程序开发中经常使用到的编码方法.它是一种基于用64个可打印字符来表示二进制数据的表示方法.它通常用作存储.传输一些二进制数据编码方法!也是MIME(多用途互联网邮件扩展,主要用 ...
- Android 使用版本控制工具时添加忽略文件方式
一.使用SVN管理项目时,添加忽略文件的方式 Android Studio 配合SVN时,添加忽略文件相对简单,首先打开项目的Settings选项,切换到Version Control下的Ignore ...