一步到位的hello world


首先一个简单的C语言版本的hello world例子,保存在文件hello.c中。

#include <stdio.h>

int main()
{
printf("hello world\n");
}

一般而言,我们通常可以使用gcc命令将其转化为可执行程序

gcc -o hello hello.c

执行上面命令后,就会在当前目录生产一个hello的可执行文件。在Centos 64位机器上执行file hello,可以得到

hello: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), not stripped

直接执行./hello即可在控制台输出hello world。

条分缕析的hello world


为了说明C语言源程序是如何转化为最终的可执行文件,首先看下面这个图



下面来分布讲解

预处理(Preprocessor)阶段

这个阶段处理#开头的指示语句,hello.c中的#include<stdio.h>告知预处理器去加载stdio.h的内容,并把它插入到当前位置。

cpp hello.c > hello.i
file hello.i
# hello.i: ASCII C program text

编译(Compiler)阶段

这个阶段把C语言源程序编译为汇编程序,不同高级语言经由其编译器处理后,得到的同样的汇编语言。

cc -S hello.i   #会生成 hello.s 文件
file hello.s
# hello.s: ASCII assembler program text

组装(Assembly)阶段

这一阶段把汇编语言翻译为机器码,结果保存在称为relocatable object program/file的文件中,以ELF(Executable and Linkable Format)格式存储(包含一个符号表,没有striped过),一般以.o结尾。

as -o hello.o hello.s
file hello.o
# hello.o: ELF 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV), not stripped

链接(Linking)阶段

注意到我们的hello.c程序使用了printf函数,它是由C语言的标准库函数,由C语言编译器提供,printf函数应该会存在于一个printf.o的文件中,我们需要某种手段把它合并到我们的hello.o中,链接器就是做这件事的。最终生成的为一个称为executable object file的文件,它可以被装载进内存并且执行。

# -lc 指定加载libc.a
ld -o hello /usr/lib64/crt*.o hello.o -lc

如果按照上面方式操作,可执行文件hello能够创建出来,但是运行./hello会报错

-bash: ./hello: /lib/ld64.so.1: bad ELF interpreter: No such file or directory

貌似是路径不对,到这里,你可能会想到gcc为什么能够一次成功,gcc是怎么调用ld的呢?我们可以通过-v选项来查看gcc调用ld时的参数

$ gcc -v hello.o -o 123
Using built-in specs.
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-thre
ads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj
-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --disable-plugin --w
ith-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=x86_64-redhat-linux
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-55)
/usr/libexec/gcc/x86_64-redhat-linux/4.1.2/collect2 --eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/l
d-linux-x86-64.so.2 -o 123 /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux
/4.1.2/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.1.2
-L/usr/lib/gcc/x86_64-redhat-linux/4.1.2 -L/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64 -L/lib/../lib64 -L/usr/
lib/../lib64 hello.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86
_64-redhat-linux/4.1.2/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crtn.o

这里重点是collect2这句,因为collect2可以看作ld功能相同的程序,为了方便阅读,我这里手动换了下行

--hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2
-o 123
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtbegin.o
-L/usr/lib/gcc/x86_64-redhat-linux/4.1.2
-L/usr/lib/gcc/x86_64-redhat-linux/4.1.2
-L/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64
-L/lib/../lib64
-L/usr/lib/../lib64 hello.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed
-lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtend.o
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crtn.o

可以看到,gcc在做链接时传入了这么多参数,至于其中的原因,就比较麻烦了,改日再写一篇文章介绍,今天先到这里。

参考


《深入理解计算机系统》☞hello world背后的故事的更多相关文章

  1. printf背后的故事

    printf背后的故事 说起编程语言,C语言大家再熟悉不过.说起最简单的代码,Helloworld更是众所周知.一条简单的printf语句便可以完成这个简单的功能,可是printf背后到底做了什么事情 ...

  2. Mac OS X 背后的故事

    Mac OS X 背后的故事 作者: 王越  来源: <程序员>  发布时间: 2013-01-22 10:55  阅读: 25840 次  推荐: 49   原文链接   [收藏]   ...

  3. 你好,C++(4)2.1.3 我的父亲母亲:编译器和链接器 2.1.4 C++程序执行背后的故事

    2.1.3  我的父亲母亲:编译器和链接器 从表面上看,我是由Visual Studio创建的,而实际上,真正负责编译源代码创建生成可执行程序HelloWorld.exe的却是Visual Studi ...

  4. elf 文件格式探秘——程序运行背后的故事

    摘要:本文主要讲解elf文件格式,通过readelf命令结合底层的相关数据结构,讲解相关内容,分析程序运行的基本原理. 本文来源:elf 文件格式探秘——程序运行背后的故事 http://blog.c ...

  5. 腾讯技术分享:微信小程序音视频技术背后的故事

    1.引言 微信小程序自2017年1月9日正式对外公布以来,越来越受到关注和重视,小程序上的各种技术体验也越来越丰富.而音视频作为高速移动网络时代下增长最快的应用形式之一,在微信小程序中也当然不能错过. ...

  6. 背后的故事之 - 快乐的Lambda表达式(一)

    快乐的Lambda表达式(二) 自从Lambda随.NET Framework3.5出现在.NET开发者眼前以来,它已经给我们带来了太多的欣喜.它优雅,对开发者更友好,能提高开发效率,天啊!它还有可能 ...

  7. 背后的故事之 - 快乐的Lambda表达式(二)

    快乐的Lambda表达式 上一篇 背后的故事之 - 快乐的Lambda表达式(一)我们由浅入深的分析了一下Lambda表达式.知道了它和委托以及普通方法的区别,并且通过测试对比他们之间的性能,然后我们 ...

  8. ASP.NET Web API自身对CORS的支持: EnableCorsAttribute特性背后的故事

    从编程的角度来讲,ASP.NET Web API针对CORS的实现仅仅涉及到HttpConfiguration的扩展方法EnableCors和EnableCorsAttribute特性.但是整个COR ...

  9. 《深入理解计算机系统V2》学习指导

    <深入理解计算机系统V2>学习指导 目录 图书简况 学习指导 第一章 计算机系统漫游 第二章 信息的表示和处理 第三章 程序的机器级表示 第四章 处理器体系结构 第五章 优化程序性能 第六 ...

  10. DbUtility v3 背后的故事

    DbUtility v3 背后的故事 时间 DbUtility v3构思了差不多大半年,真正开发到第一个版本发布到NuGet却只花了50天.中途大量时间在完善 Jumony 3,只有三周来开发DbUt ...

随机推荐

  1. delegate:动态绑定js事件

    $('.videomodule').delegate("span", "click", function() { var i = $(this).index() ...

  2. springboot后端controller参数接收

    参考:https://blog.csdn.net/a532672728/article/details/78057218 get方法 : 1. http://localhost:8080/0919/t ...

  3. P4178 Tree 点分治

    思路:点分治 提交:1次 题解: 要求权值和\(\leq K\) 的路径,我们可以类比点分治的模板,把长为\(len\)是否存在,改为\(len\)的路径的条数,并用用树状数组维护前缀和,这样就可以求 ...

  4. P2587 [ZJOI2008]泡泡堂 神仙贪心

    思路:贪心 提交:1次(看了题解$QwQ$) 题解: 若我方最弱可以干掉对方最弱,则干: 否则若我方最强可以干掉对方最强,则干: 否则若我方最弱与对方最强平手,则平: 其实貌似一二条是可以互换的,主要 ...

  5. 51nod 1086

    https://www.cnblogs.com/TnT2333333/p/6879709.html 二进制优化多重背包 怎么用二进制优化多重背包,举一个例子就明白了. 如果要放n个苹果,可以将n个苹果 ...

  6. 解决zabbix的cannot allocate shared memory of size错误

    问题状态:zabbix_server 不能启动,系统CentOS 6.7 原因分析:这是因为内核对share memory的限制造成的. 用到如下命令ipcs [-m|l|a],sysctl [-a| ...

  7. 2019.7.9 校内测试 T3 15数码问题

    这一次是交流测试?边交流边测试(滑稽 15数码问题 大家应该都玩过这个15数码的游戏吧,就在桌面小具库那里面哦. 一看到这个题就知道要GG,本着能骗点分的原则输出了 t 个无解,本来以为要爆零,没想到 ...

  8. mac: jenkins+ant+jmeter接口测试

    最近研究Jenkins平台上使用ant进行集成测试,在网上查阅了很多资料,将 jenkins+ant+jmeter简单使用方法记录下来,方便以后查阅.有很多不足之处,后期不断优化. 一.环境搭建 1. ...

  9. Django基础之form表单的补充进阶

    1. 应用Bootstrap样式 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  10. @Transactional注解详细用法

    概述 事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性.Spring Framework对事务管理提供了一致的抽象,其特点如下: 为不同的事务API提供一致的编程模型, ...