全身心理解程序的转换(编译)过程

> 计算机的指令分类:

伪指令:机器指令序列

机器指令:机器指令和汇编指令一一对应

汇编指令:机器指令的汇编语言

微指令:微程序级指令,属于硬件范畴,这点组成原理上有讲过。

其中汇编指令和机器指令都属于机器级指令。

启发:

汇编在转换为机器指令时并没有进行优化,相同的汇编程序在执行时带来的效率差 别应该源于硬件的不同。

ISA(指令级体系结构)的存在使得汇编更方便移植。

在此可见ISA在整个计算机系统抽象层中的重要性。

> 生成机器代码的过程:

用 GCC + Linux + IA32 平台进行实验

程序转换四个步骤:

1. 预处理

引入#include<文件>和处理宏语句

2. 编译

将处理后的源程序文件编译成相应的汇编语言程序。

3. 汇编

将汇编源程序文件转换为可重定位的机器语言目标代码文件。

4. 链接

由连接器将多个可重定位的机机器语言目标程序文件以及库例程连接起来,得到可执行文件。

> 这里以hello.cpp为例

-第一步

> gcc -E hello.cpp -o hello.i

因为引入了<iostream>输入输出流文件,所以.......预处理后特别长

hello.i 大小:411KB

注意到了吗?在这里我用gcc对c++源文件进行预处理居然也是可以的。

好奇提问:GCC 对于 c 和 cpp 的预处理操作是相同的吗? gcc -E

加一条指令:g++ -E hello.cpp -o hello++.i

从实验结果上:

GCC 对于cpp的预处理跟G++效果相同。但后续就完全不同了。

-第二步

> g++ -S hello.i -o hello.s

得到的汇编指令有80行

hello.s 大小:2KB

-第三步

> g++ -c hello.s -o hello.o

目标程序 hello.o 有3KB (这里只生成了一个目标文件)

-第四步

> g++ hello.o -o hello

执行程序大小: 9KB

-执行吧少年!!

./hello

Hola!

------正文完------

附录:

g++ manual 摘录:

-E Stop after the preprocessing stage; do not run the compiler

proper. The output is in the form of preprocessed source code,

which is sent to the standard output.

Input files that don‘t require preprocessing are ignored.

-c Compile or assemble the source files, but do not link. The

linking stage simply is not done. The ultimate output is in the

form of an object file for each source file.

By default, the object file name for a source file is made by

replacing the suffix .c, .i, .s, etc., with .o.

Unrecognized input files, not requiring compilation or assembly,

are ignored.

-S Stop after the stage of compilation proper; do not assemble. The

output is in the form of an assembler code file for each non-

assembler input file specified.

By default, the assembler file name for a source file is made by

replacing the suffix .c, .i, etc., with .s.

Input files that don‘t require compilation are ignored.

-o file

Place output in file file. This applies to whatever sort of

output is being produced, whether it be an executable file, an

object file, an assembler file or preprocessed C code.

If -o is not specified, the default is to put an executable file

in a.out, the object file for source.suffix in source.o, its

assembler file in source.s, a precompiled header file in

source.suffix.gch, and all preprocessed C source on standard

output.

更多关于gcc/g++的使用请自行查询

hello.cpp 源文件

# include<iostream>

using namespace std;

int main()

{

cout<<"Hola!"

}

(正向编译)汇编指令源程序(AT&T格式):

.file "hello.cpp"
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.section .rodata
.LC0:
.string "Hola!"
.text
.globl main
.type main, @function
main:
.LFB971:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %esi
movl $_ZSt4cout, %edi
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE971:
.size main, .-main
.type _Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB975:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
cmpl $1, -4(%rbp)
jne .L3
cmpl $65535, -8(%rbp)
jne .L3
movl $_ZStL8__ioinit, %edi
call _ZNSt8ios_base4InitC1Ev
movl $__dso_handle, %edx
movl $_ZStL8__ioinit, %esi
movl $_ZNSt8ios_base4InitD1Ev, %edi
call __cxa_atexit
.L3:
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE975:
.size _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
.type _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB976:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $65535, %esi
movl $1, %edi
call _Z41__static_initialization_and_destruction_0ii
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE976:
.size _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
.section .init_array,"aw"
.align 8
.quad _GLOBAL__sub_I_main
.hidden __dso_handle
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",@progbits

  

有道云笔记粘贴过来格式丢了个八九不离十

转载请注明出处 :)

时间: 2024-10-17 10:06:59

全身心理解程序的转换(编译)过程的相关文章

用gcc编译c语言程序以及其编译过程

对于初学c语言编程的我们来说,学会如何使用gcc编译器工具,对理解c语言的执行过程,加深对c语言的理解很重要!!! 1.预编译 --> 2.编译 --> 3.汇编 --> 4.链接----------------------------------------------------------------------------- 0.编写c代码,并输入以下如图代码,生成c文件hello.c. ----------------------------------------------

[转]c++应用程序文件的编译过程

原文地址 这里讲下C++文件的编译过程及其中模板的编译过程: 一:一般的C++应用程序的编译过程.    一般说来,C++应用程序的编译过程分为三个阶段.模板也是一样的. 在cpp文件中展开include文件. 将每个cpp文件编译为一个对应的obj文件. 连接obj文件成为一个exe文件(或者其它的库文件). 下面分别描述这几个阶段.1.include文件的展开.    include文件的展开是一个很简单的过程,只是将include文件包含的代码拷贝到包含该文件的cpp文件(或者其它头文件)

liunx程序编译过程介绍及bug解决

1.  首先来看下一般的liunx中C程序具体的编译过程 参考网站http://blog.csdn.net/gengyichao/article/details/6544266上的图 将编写的一个.c文件(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译阶段和链接这两个主要阶段: 1) 编译阶段先通过“编译器”把一个.c 文件编译成 .s的汇编文件:再经过“汇编器”把这个.s的汇编代码汇编成.o 目标文件: 注:把预处理完的文件进行一系列的词法分析.语法分析.语义分析及优化后产生

GCC编译过程

以下是C程序一般的编译过程: gcc的编译流程分为四个步骤,分别为:· 预处理(Pre-Processing) 对C语言进行预处理,生成*.i文件.· 编译(Compiling) 将上一步生成的*.i文件编译生成汇编语言文件,后缀名为*.s· 汇编(Assembling) 将汇编语言文件*.s经过汇编,生成目标文件,后缀名为*.o· 链接(Linking) 将各个模块的*.o文件链接起来,生成最终的可执行文件 示例代码: 1 //hello.c源代码 2 3 #include<stdio.h>

Linux 程序编译过程的来龙去脉

大家肯定都知道计算机程序设计语言通常分为机器语言.汇编语言和高级语言三类.高级语言需要通过翻译成机器语言才能执行,而翻译的方式分为两种,一种是编译型,另一种是解释型,因此我们基本上将高级语言分为两大类,一种是编译型语言,例如C,C++,Java,另一种是解释型语言,例如Python.Ruby.MATLAB .JavaScript. 本文将介绍如何将高层的C/C++语言编写的程序转换成为处理器能够执行的二进制代码的过程,包括四个步骤: 预处理(Preprocessing) 编译(Compilati

linux程序编译过程

大家肯定都知道计算机程序设计语言通常分为机器语言.汇编语言和高级语言三类.高级语言需要通过翻译成机器语言才能执行,而翻译的方式分为两种,一种是编译型,另一种是解释型,因此我们基本上将高级语言分为两大类,一种是编译型语言,例如C,C++,Java,另一种是解释型语言,例如Python.Ruby.MATLAB .JavaScript. 本文将介绍如何将高层的C/C++语言编写的程序转换成为处理器能够执行的二进制代码的过程,包括四个步骤: 预处理(Preprocessing) 编译(Compilati

Keil编译过程及程序在Flash和SRAM的空间分配

1. keil编译介绍 当使用keil进行单片机的开发时,运行一段程序后,在output输出框会看到如下图的结果. 图1 keil 的output框 其中,Compiler编译器,使用的版本是 V5.06,程序会先经过编译.后链接linking生成可执行的代码,如果要下载单片机的Flash上,还需要转换成二进制(bin)或者十六进制(hex)的文件.具体过程如下: 图2 keil的编译过程 值得注意的是,经过编译后,并不会给变量赋地址生(.o文件),只有经过链接器链接后变量才有地址,链接的作用可

C语言程序编译过程

最近在编译DM8168的ARM端程序时经常出现未定义.重定义等报错,由于源码文件多,包含关系比较多,所以自己添加时容易乱.深深的体会到,好的代码风格是如此重要,之前也在看代码重构,以后应该更加注意代码的质量.经思考总结规律如下: 1.公用的数据结构等写为一个头文件,其他源文件包含此头文件.同时为了让不同源文件里的函数都可以使用,公用的函数可以放在此头文件中声明. 2.其他源文件里声明的变量,如果想在另一个文件里用,需要extern声明,这样可以避免各种全局变量的交互混杂. 理解的比较浅,希望高人

C程序编译过程

1.1程序被其他程序翻译成不同的格式 1.hello.c #include <stdio.h> int main() { printf("hello world\n"); } 2.编译过程 3.编译系统 预处理器.编译器.汇编器和链接器一起构成了编译系统 预处理阶段.预处理器(cpp)根据以字符#开通的命令,修改原始的C程序.比如hello.c中第1行的#include<stdio.h>命令告诉预处理器读取系统头文件stdio.h的内容,并把它直接插入到程序的文