`
yanfaguanli
  • 浏览: 662302 次
文章分类
社区版块
存档分类
最新评论

从hello world理解Linux的编译系统

 
阅读更多


从helloworld理解Linux的编译系统


本文将以一个简单的helloworld程序由编写到运行的整个过程来解释Linux的编译系统的原理。

首先,用C语言写一个程序hello.c

内容如下:

  1. #include<stdio.h>
  2. intmain()
  3. {
  4. printf("helloworld\n");
  5. }

保存后,用gcc进行编译:

gcc-ohellohello.c

然后执行编译后的hello程序:

./hello或者hello

执行结果如下:

helloworld

hello程序的生命周期是从一个高级C语言程序开始的,因为这种形式能够被人读懂。然而,为了在系统上运行hello.c程序,每条C语句都必须被其他程序转化为一系列的低级机器语言指令。然后这些指令按照一种称为可执行目标程序的格式打好包,并以二进制磁盘文件的形式存放起来。目标程序也称为可执行目标文件

在Unix系统上,从源文件到目标文件的转化是由编译器驱动程序完成的:

unix>gcc-ohellohello.c

在这里,gcc命令依次调用了多个程序(分别为:预处理器——>编译器(当然这里指GCC编译器)——>汇编器——>链接器),将源程序文件hello.c翻译成一个可执行目标文件hello。这个翻译的过程可分为四个阶段完成,如下图所示。执行这四个阶段的程序(预处理器、编译器、汇编器和链接器)一起构成了编译系统(compilationsystem)。

注意:gcc命令是调用多个程序,而不是仅调用GCC编译器,GCC编译器只是编译系统的一部分。具体参考下图:

编译系统

预处理阶段。预处理器(cpp)根据以字符#开头的命令,修改原始的C程序。比如hello.c中第1行的#include<stdio.h>命令告诉预处理器读取系统头文件stdio.h的内容,并把它直接插入到程序文本中。结果就得到了另一个C程序,通常是以.i作为文件扩

展名。

编译阶段。编译器(cc1)将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。汇编语言程序中的每条语句都以一种标准的文本格式确切地描述了一条低级机器语言指令。汇编语言是非常有用的,因为它为不同高级语言的不同编译器提供了通

用的输出语言。例如,C编译器和Fortran编译器产生的输出文件用的都是一样的汇编语言。

汇编阶段。接下来,汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序(relocatableobjectprogram)的格式,并将结果保存在目标文件hello.o中。hello.o文件是一个二进制文件,它的字节编码是机器语言指令而不是字符。如果我们在文本编辑器中打开hello.o文件,看到的将是一堆乱码。

链接阶段。请注意,hello程序调用了printf函数,它是每个C编译器都会提供的标准C库中的一个函数。printf函数存在于一个名为printf.o的单独的预编译好了的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。链接器(ld)就负责处理这种合并。结果就得到hello文件,它是一个可执行目标文件(或者简称为可执行文件),可以被加载到内存中,由系统执行。


说到这里,相信大家对Linux的编译系统已经有了初步的认识,那么,我们为什么要去深入的了解编译系统呢,主要原因如下

优化程序性能。现代编译器都是成熟的工具,通常可以生成很好的代码。作为程序员,我们无需为了写出高效代码而去了解编译器的内部工作。但是,为了在C 程序中做出好的编码选择,我们确实需要了解一些机器代码以及编译器将不同的C 语句转化为机器代码的方式。例如,一个switch 语句是否总是比一系列的if-then-else 语句高效得多?一个函数调用的开销有多大? while 循环比for 循环更有效吗?指针引用比数组索引更有效吗?为什么将循环求和的结果放到一个本地变量中,与将其放到一个通过引用传递过来的参数中相比,运行速度要快很多呢?为什么我们只是简单地重新排列一下一个算术表达式中的括号就能让一个函数运行得更快?

理解链接时出现的错误。根据我们的经验,一些最令人困扰的程序错误往往都与链接器操作有关,尤其是当你试图构建大型的软件系统时。例如,链接器报告它无法解析一个引用,这是什么意思?静态变量和全局变量的区别是什么?如果你在不同的C 文件中定义了名字相同的两个全局变量会发生什么?静态库和动态库的区别是什么?我们在命令行上排列库的顺序有什么影响?最严重的是,为什么有些链接错误直到运行时才会出现?

避免安全漏洞。多年来,缓冲区溢出错误是造成大多数网络和Internet 服务器上安全漏洞的主要原因。存在这些错误是因为很少有人能理解限制他们从不受信任的站点接收数据的数量和格式的重要性。学习安全编程的第一步就是理解数据和控制信息存储在程序栈上的方式会引起的后果。然而这些都与对编译系统的理解密不可分。
分享到:
评论

相关推荐

    基于linux的HelloWorld程序实验

    基于linux的HelloWorld程序实验

    深入浅出hello world

    从一个简单的hello,world程序开始,经过预处理、编译、汇编、链接、加载各个步骤详细介绍程序从编辑到执行的过程。深入的讲解了linux下程序的编译过程,并且讲解了linux kernel系统调用的相关知识。

    linux 驱动开发之linux vscode环境搭建以及第一个驱动 helloWorld

    下载linux版的vscode ,并且安装 我用的板子是nxp的imx6ull,下载nxp的的arm交叉编译工具链和他们的内核(也可以下载官方版本的...创建一个helloworld的文件夹mkdir helloworld ,创建一个c文件:touch helloworld.c 用vscod

    一个简单的x86架构下的汇编语言脚本示例,在控制台上输出"Hello, World!"

    一个简单的x86架构下的汇编语言脚本示例,用于在Linux环境下使用NASM汇编器编写一个程序,该程序会在控制台上输出"Hello, World!"。 编译与运行: 首先,你需要安装NASM汇编器。在大多数Linux发行版中,你可以使用包...

    Linux操作系统下C++编程

    在Windows下有TC, BC, VC等编译器,它们极大地方便了程序的编辑编译等,在Windows下你只需要看明白菜单就可以了。...本文以一个最简单也是最经典的Hello World为例介绍了Linux操作系统下C++编程的方法。

    (1)学习 Linux 内核的系统调用方法 理解并掌握 Limux 系统调用的实现框架、用户界面、参数传递、进入返回过程

    (2)使用cd /usr/src/linux-5.4.1/kernel进入kernel目录并打开sys.c文件加入打印”hello world”的函数 (3)使用命令gedit syscalls.h中添加上述函数的函数声明 (4)在调用表中选择一个空的可用的调用号(因为...

    linux操作系统+linux下编程+实验报告及代码和操作过程+期末复习

    (1)编写“Hello World”程序,编译并运行,记录其结果。 (2)编写程序计算cos(3.14/2),编译并运行,记录其计算结果。 (3)编写计算阶乘的C语言程序,编译并运行,记录其计算结果。 要求:将main主程序、计算...

    Linux实验课设报告

    4、Linux shell编程:输出Hello World、获取系统信息、获取网卡信息、监控CPU负载 5、Linux内核编译与运行:Busybox准备、环境配置、编译最小文件系统、编译内核、运行QEMU 6、Linux内核模块编程:内核模块编程、...

    Linux环境使用g++编译C++方法总结

    下面是一个保存在文件 helloworld.cpp 中一个简单的 C++ 程序的代码: /* helloworld.cpp */ #include int main(int argc,char *argv[]) { std::cout &lt;&lt; hello, world &lt;&lt; std::endl; return(0); } ...

    一个简单的linux汇编语言程序

    Intel语法 Intel语法是由Intel公司为其处理器编写官方文档时所采用的语法。...编译:nasm -f elf32 hello_world.asm -o hello_world.o 链接:ld -m elf_i386 hello_world.o -o hello_world 运行:./hello_world

    Linux下编译C程序的过程

    printf(Hello World!\n); return 0; } 对于test.c,我们常用一步编译到位的命令是: gcc -o test test.c 或者 gcc test.c -o test 实际上,上面的这个编译命令包含了四个阶段的处理,即预处理(也称预编译,...

    Linux程序设计参考书-六部

    Linux编程实例第1章Hello, World1.1 内核模块的Makefiles文件1.2 多重文件内核模块第2章字符设备文件第3章/proc文件系统第4章把/proc用于输入第5章把设备文件用于输入第6章启动参数第7章系统调用第8章阻塞处理第9章...

    Linux从零入门实战-2019年七月Z线.txt

    第一阶段 Linux快速入门掌握Linux的常用操作命令 第一讲 Linux介绍 知识点1: Linux发展简史与黑客文化 知识点2: 安装Linux系统, 以Ubuntu...实战项目: 自行编译构建一个Linux系统 第十讲 Linux操作系统常见试题解析

    Linux内核驱动模块编程指南 (内核版本2.2, 2.4)The Linux Kernel Module Programming Guide CHS

    2.5. Hello World (part 4): 内核模块证书和内核模块文档说明 2.6. 从命令行传递参数给内核模块 2.7. 由多个文件构成的内核模块 3. 开始热身 3.1. 内核模块和用户程序的区别 4. 字符设备文件 4.1. 字符设备驱动程序 ...

    xilinx zynq7000移植sqlite3

    在xilinx zynq7000 Linux系统移植sqlite3,报告库文件

    Linux编程从入门到精通

    第1章 Hello, World 145 1.1 内核模块的Makefiles文件 146 1.2 多重文件内核模块 147 第2章 字符设备文件 149 第3章 /proc文件系统 158 第4章 把/proc用于输入 162 第5章 把设备文件用于输入 170 第6章 启动参数 182...

    Qt Creator 的安装和hello world 程序+其他程序的编写--不是一般的好

    我们这里的工程名为helloworld。 6.这时软件自动添加基本的头文件,因为这个程序我们不需要其他的功能,所以 直接点击Next。 7.我们将base class 选为QDialog 对话框类。然后点击Next。 8.点击Finish,完成工程的...

    Linux下的CppUnit 的HelloWorld手记

    操作系统系统:Ubuntu6,g++ 软件版本:cppunit-1.10.2.tar.gz (1)获得源码:  到cppunit.sourceforge.net上下载源代码。将其复制到到linux下或者是直接使用wget下载到linux下。 (2)解压缩: 使用以下...

    UNIX/LINUX及其使用环境

    1、通过WINDOWS操作系统中的远程登录程序telnet.exe 登录UNIX。...4、用vi编写一个简单的、显示"Hello,World!"的C程序,用gcc编译并观察编译后的结果。 5、利用gdb调试该程序。 6、运行生成的可执行文件。

    linux驱动学习去开发入门

    make -C /home/tekkaman/working/SBC2440/linux-2.6.22.2 M=/home/tekkaman/working/Linuxdriver/Helloworld modules make[1]: Entering directory `/home/tekkaman/working/SBC2440/linux-2.6.22.2' CC [M] /home/...

Global site tag (gtag.js) - Google Analytics