程序的执行
一、平台无关性
平台:计算机体系结构、操作系统、开发平台(编译器、链接器)
不同的计算机体系结构有不同的指令集,
汇编语言、机器语言是针对具体的体系结构的指令集写的程序,只能在特定的平台上运行
C语言可以在不同体系结构的计算机上使用特定的C编译器,编译成不同体系结构的机器指令,高级语言都具有平台无关性
二、程序的执行过程
1、编译执行(C/C++)
(1)写源代码,保存为pro.c
(2)运行编译器进行编译,把源代码翻译成机器指令,再加上一些描述信息,生成一个新的文件a.out
(3) a.out为可执行文件,该文件可被操作系统加载运行,计算机执行该文件中由编译器生成的指令。
以下 原文来自:http://www.vcgood.com/bbs/forum_posts.asp?tid=1400
编译,编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格式的要求链接生成可执行程序。
C源程序头文件-->预编译处理(cpp)-->编译程序本身-->优化程序-->汇编程序-->链接程序-->可执行文件
1.编译预处理
读取c源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理
[析] 伪指令主要包括以下四个方面
(1)
宏定义指令,如#define Name
TokenString,#undef等。对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,但作为字符串常量的
Name则不被替换。对于后者,则将取消对某个宏的定义,使以后该串的出现不再被替换。
(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif,等等。这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉
(3)头文件包含指令,如#include "FileName"或者#include
<FileName>等。在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。采用
头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再
在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。
包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下。在程序中#include它们要使用尖括号
(<>)。另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。
(4)特殊符号,预编译程序可以识别一些特殊的符号。例如在源程序中出现的LINE标识将被解释为当前行号(十进制数),FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。
预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没
有经过预处理的源文件是相同的,但内容有所不同。下一步,此输出文件将作为编译程序的输出而被翻译成为机器指令。
2.编译阶段
经过预编译得到的输出文件中,将只有常量。如数字、字符串、变量的定义,以及C语言的关键字,如main,if,else,for,while,
{,},+,-,*,\,等等。预编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示
或汇编代码。
3.优化阶段
优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系。优化一部分是对中间代码的优化。
这种优化不依赖于具体的计算机。另一种优化则主要针对目标代码的生成而进行的。上图中,我们将优化阶段放在编译程序的后面,这是一种比较笼统的表示。
对于前一种优化,主要的工作是删除公共表达式、循环优化(代码外提、强度削弱、变换循环控制条件、已知量的合并等)、复写传播,以及无用赋值的删除,等等。
后一种类型的优化同机器的硬件结构密切相关,最主要的是考虑是如何充分利用机器的各个硬件寄存器存放的有关变量的值,以减少对于内存的访问次数。另
外,如何根据机器硬件执行指令的特点(如流水线、RISC、CISC、VLIW等)而对指令进行一些调整使目标代码比较短,执行的效率比较高,也是一个重
要的研究课题。
经过优化得到的汇编代码必须经过汇编程序的汇编转换成相应的机器指令,方可能被机器执行。
4.汇编过程
汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。
目标文件由段组成。通常一个目标文件中至少有两个段:
代码段 该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般却不可写。
数据段 主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。
UNIX环境下主要有三种类型的目标文件:
(1)可重定位文件 其中包含有适合于其它目标文件链接来创建一个可执行的或者共享的目标文件的代码和数据。
(2)共享的目标文件 这种文件存放了适合于在两种上下文里链接的代码和数据。第一种事链接程序可把它与其它可重定位文件及共享的目标文件一起处理来创建另一个目标文件;第二种是动态链接程序将它与另一个可执行文件及其它的共享目标文件结合到一起,创建一个进程映象。
(3)可执行文件 它包含了一个可以被操作系统创建一个进程来执行之的文件。
汇编程序生成的实际上是第一种类型的目标文件。对于后两种还需要其他的一些处理方能得到,这个就是链接程序的工作了。
5.链接程序
由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号
(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。
链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。
根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:
(1)静态链接 在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。
(2)动态链接 在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录
下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执
行程序中记录的信息找到相应的函数代码。
对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时
能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能
上损害。
经过上述五个过程,C源程序就最终被转换成可执行文件了。缺省情况下这个可执行文件的名字被命名为a.out。
2、解释执行(脚本语言,ruby,php,javascript等)
(1)写源代码
(2)读取源代码,解释执行,不需要编译成包含机器指令的可执行文件,读取一句,执行一句
puts "sdsdsds"
puts ll
第一句正常执行
第二句报错
sdsdsds
ru.rb:2:in `<main>': undefined local variable or method `ll' for main:Object (NameError)
3、虚拟机执行(java):将编译与解释结合起来
(1)写源代码
(2)编译器读取源代码,编译生成虚拟机的字节码
(3)虚拟机执行字节码。
来自http://java.chinaitlab.com/Jvm/21875.html
Java应用程序的开发周期包括编译、下载
、解释和执行几个部分。Java编译程序将Java源程序翻译为JVM可执行代码?字节码。这一编译过程同C/C++
的
编译有些不同。当C编译器编译生成一个对象的代码时,该代码是为在某一特定硬件平台运行而产生的。因此,在编译过程中,编译程序通过查表将所有对符号的引
用转换为特定的内存偏移量,以保证程序运行。Java编译器却不将对变量和方法的引用编译为数值引用,也不确定程序执行过程中的内存布局,而是将这些符号
引用信息保留在字节码中,由解释器在运行过程中创立内存布局,然后再通过查表来确定一个方法所在的地址。这样就有效的保证了Java的可移植性和安全
性。
运行JVM字节码的工作是由解释器来完成的。解释执行过程分三部进行:代码的装入、代码的校验和代码的执行。装入代码的工作由"类装载器"(class
loader)完成。类装载器负责装入运行一个程序需要的所有代码,这也包括程序代码中的类所继承的类和被其调用的类。当类装载器装入一个类时,该类被放
在自己的名字空间中。除了通过符号引用自己名字空间以外的类,类之间没有其他办法可以影响其他类。在本台计算机上的所有类都在同一地址空间内,而所有从外
部引进的类,都有一个自己独立的名字空间。这使得本地类通过共享相同的名字空间获得较高的运行效率,同时又保证它们与从外部引进的类不会相互影响。当装入
了运行程序需要的所有类后,解释器便可确定整个可执行程序的内存布局。解释器为符号引用同特定的地址空间建立对应关系及查询表。通过在这一阶段确定代码的
内存布局,Java很好地解决了由超类改变而使子类崩溃的问题,同时也防止了代码对地址的非法访问。
随后,被装入的代码由字节码校验器进行检查。校验器可发现操作数栈溢出,非法数据类型转化等多种错误。通过校验后,代码便开始执行了。
Java字节码的执行有两种方式:
1.即时编译方式:解释器先将字节码编译成机器码,然后再执行该机器码。
2.解释执行方式:解释器通过每次解释并执行一小段代码来完成Java字节码程 序的所有操作。
通常采用的是第二种方法。由于JVM规格描述具有足够的灵活性,这使得将字节码翻译为机器代码的工作
具有较高的效率。对于那些对运行速度要求较高的应用程序,解释器可将Java字节码即时编译为机器码,从而很好地保证了Java代码的可移植性和高性能。
编译与解释执行的优缺点:
来自http://hi.baidu.com/savioryu/blog/item/7cae5aa3c2c864a7cbefd006.html
1、运行效率:
编译语言需要编译一次,运行直接执行、不需要翻译,所以编译型语言的程序执行效率高。而解释语言则不同,解释型语言的程序不需要编译,省了道工序,解释性
语言在运行程序的时候才翻译,比如解释型basic语言,专门有一个解释器能够直接执行basic程序,每个语句都是执行的时候才翻译。这样解释性语言每
执行一次就要翻译一次,效率比较低。
解释执行的语言因为解释器不需要直接同机器码打交道所以实现起来较为简单、而且便于在不同的平台上面移植,这一点从现在的编程语言解释执行的居多就能看出
来,如 Visual Basic、Visual Foxpro、Power Builder、Java...等。编译执行的语言因为要直接同CPU
的指令集打交道,具有很强的指令依赖性和系统依赖性,但编译后的程序执行效率要比解释语言要高的多,象现在的 Visual C/C++、Delphi
等都是很好的编译语言。
2、代码安全性
对于解释语言与编译语言所编制出来的代码安全性上而言,可以说是各有优缺点。曾经在 Windows 下跟踪调式过 VB
程序的朋友一般都知道,程序代码 99% 的时间里都是在 VBRUNxx 里转来转去,根本看不出一个所以然来。 这是因为你跟踪的是 VB
的解释器,要从解释器中看出代码的目的是什么是相当困难的。但解释语言有一个致命的弱点,那就是解释语言的程序代码都是以伪码的方式存放的,一旦被人找到
了伪码与源码之间的对应关系,就很容易做出一个反编译器出来,你的源程序等于被公开了一样。而编译语言因为直接把用户程序
编译成机器码,再经过优化程序的优化,很难从程序返回到你的源程序的状态,
但对于熟悉汇编语言的解密者来说,也很容易通过跟踪你的代码来确定某些代码的用途。
分享到:
相关推荐
Sql Server Profiler 监听应用程序执行的 SQL Sql Server Profiler 是 DBA 进行 SQL 监控和调优时必用的工具,对于开发人员来说,能够监控到程序运行时的 SQL,对于排障已经相当方便了。下面将详细介绍如何使用 Sql...
EXE是可执行文件的扩展名,代表“executable”,它是Windows操作系统中的一个二进制文件,用户可以直接双击运行。当应用程序被设计为exe文件时,它可以在没有安装过程的情况下直接运行,正如描述中提到的,这个工具...
在查看 DSP 程序运行时间时,用户主要关心的是代码执行的时钟周期,即 Incl. Maximum、Incl. Minimum 和 Incl. Average 三个字段。 最后,选择要剖析的函数,然后将光标放在该函数的函数名上,选择建立剖析区域按钮...
- 宏程序执行完毕后,可以选择手动停止或者设置自动停止条件。 #### 五、注意事项 - 在编写宏程序时,应注意遵循良好的编程习惯,如代码注释、变量命名清晰等。 - 对于复杂的宏程序,建议采用模块化的设计思路,...
7. **进程生存期管理**:为了确保程序执行完关键任务后才删除自身,开发者需要精确控制进程的生命周期。可能需要在主线程执行完后再删除文件,或者使用多线程技术,在子线程执行删除操作。 8. **安全考虑**:自删除...
1. **程序代码区**:这是存储程序执行指令的地方,包括编译后的机器码。这部分内存通常在程序启动时由操作系统一次性加载,并在整个程序运行过程中保持不变。 2. **文字常量区**:在这个区域,存储的是程序中的字符...
这将打包项目的所有依赖文件,并创建一个可执行的安装程序,用户可以简单地运行这个安装程序来安装你的禁止程序小软件。 7. **安全性和隐私**:需要注意的是,这样的程序可能会对用户的正常使用造成不便,也可能被...
### VisualFortran程序运行速度的优化方法 在IT领域,特别是对于从事科学计算、工程模拟等领域的开发者来说,提升程序的运行效率是非常重要的工作之一。本文将基于给定的文件内容,详细介绍如何优化Visual Fortran...
总的来说,"C#程序100实例+c#程序执行器"这个资源包将帮助学习者从理论到实践全面掌握C#编程,通过实例学习,可以提升编程技能,并且通过程序执行器,可以便捷地运行和测试自己的代码,加深对C#编程的理解。...
C++程序设计中程序执行主要分为两种方式:编译运行和单步调试。编译运行是C++程序最基本和常见的执行方式,它将源代码编译成机器能够理解和执行的二进制代码,然后通过运行该二进制代码来观察程序的执行结果。单步...
在本课程“第一课 Windows程序运行原理及程序编写流程 1.rar”中,我们将深入探讨Windows操作系统下程序的运行机制以及编写程序的基本流程。通过学习这些核心概念,开发者能够更好地理解程序是如何在计算机中被创建...
在这个例子中,`std::chrono::high_resolution_clock::now()`用于获取当前的时间点,然后在程序执行完毕后再次调用,两者之差即为程序运行时间。`std::chrono::duration_cast<std::chrono::microseconds>`用来将时间...
如果程序或系统进入不期望的状态,看门狗会在预设时间内未收到“心跳”信号(证明程序正常运行的信号)后,强制执行重启操作。 5. **守护程序(Daemon)**:守护程序是后台运行的长期服务,通常在用户登录会话之外...
在程序开发过程中,"程序运行提示"通常指的是在程序执行时显示的警告、错误或信息消息。这些提示有助于用户理解程序状态,或者在出现错误时提供反馈。在AutoIt中,可以使用`MsgBox`函数来创建这些提示对话框。例如...
软件可能通过读取系统注册表、监控进程等方式,识别并阻止指定的程序执行。 关于软件可能不报毒的情况,这可能是由于该软件的行为模式与某些杀毒软件的检测标准不同,导致杀毒软件未能识别其为安全程序。在使用时,...
总结来说,《部门程序执行程序情况检查统计表》是企业管理和监控程序运行效能的有效工具,通过对各程序的正常率进行周期性统计,有助于识别潜在问题,优化业务流程,确保企业的运营效率和稳定性。同时,这样的统计表...
【单片机基本结构及常用程序运行构架】 单片机程序设计的核心在于理解其基本...通过熟练掌握顺序、分支和循环结构,以及合理选择程序执行模型,我们可以编写出高效、可维护的单片机程序,以应对各种应用场景的需求。
这通常是指程序执行时所在的目录,即程序的可执行文件(.exe)所在的路径。在Windows操作系统中,这个信息对于动态加载库(DLLs)或者定位与程序相关的数据文件至关重要。 在C++ .NET中,我们可以利用`System::IO`...