exe文件的工作原理

5 篇文章 0 订阅

问题9

exe文件的工作原理

解决方案

HelloWorld.cs
//HelloWorld.cs by Cornfield,2001
//csc HelloWorld.cs
using System;
class HelloWorld
{
   public static void Main()
   {
     Console.WriteLine("Hello World !");
   }
}
编译输出的HelloWorld.exe是一个由中间语言(IL),元数据(Metadata)和一个额外的被编译器添加的目标平台的标准可执行文件头(比如Win32平台就是加了一个标准Win32可执行文件头)组成的PE(portable executable,可移植执行体)文件,而不是传统的二进制可执行文件--虽然他们有着相同的扩展名。中间语言是一组独立于CPU的指令集,它可以被即时编译器Jitter翻译成目标平台的本地代码。中间语言代码使得所有Microsoft.NET平台的高级语言C#,VB.NET,VC.NET等得以平台独立,以及语言之间实现互操作。元数据是一个内嵌于PE文件的表的集合。元数据描述了代码中的数据类型等一些通用语言运行时(Common Language Runtime)需要在代码执行时知道的信息。元数据使得.NET应用程序代码具备自描述特性,提供了类型安全保障,这在以前需要额外的类型库或接口定义语言(Interface Definition Language,简称IDL)。

这样的解释可能还是有点让人困惑,那么我们来实际的解剖一下这个PE文件。我们采用的工具是.NET SDK Beta2自带的ildasm.exe,它可以帮助我们提取PE文件中的有关数据。我们键入命令"ildasm /output:HelloWorld.il HelloWorld.exe",一般可以得到两个输出文件:helloworld.il和helloworld.res。其中后者是提取的资源文件,我们暂且不管,我们来看helloworld.il文件。我们用"记事本"程序打开可以看到元数据和中间语言(IL)代码,由于篇幅关系,我们只将其中的中间语言代码提取出来列于下面,有关元数据的表项我们暂且不谈:


//  Microsoft (R) .NET Framework IL Disassembler.  Version 1.1.4322.573
//  Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.

.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z/V.4..
  .ver 1:0:5000:0
}
.assembly Class2
{
  // --- 下列自定义属性会自动添加,不要取消注释 -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(bool,
  //                                                                                bool) = ( 01 00 00 01 00 00 )
  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module Class2.exe
// MVID: {A9D4A2DC-A401-4F5F-B16F-B3D40F584E59}
.imagebase 0x00400000
.subsystem 0x00000003
.file alignment 512
.corflags 0x00000001
// Image base: 0x070c0000
//
// ============== CLASS STRUCTURE DECLARATION ==================
//
.class public auto ansi beforefieldinit Test
       extends [mscorlib]System.Object
{
} // end of class Test


// =============================================================


// =============== GLOBAL FIELDS AND METHODS ===================


// =============================================================


// =============== CLASS MEMBERS DECLARATION ===================
//   note that class flags, 'extends' and 'implements' clauses
//          are provided here for information only

.class public auto ansi beforefieldinit Test
       extends [mscorlib]System.Object
{
  .method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    // 代码大小       72 (0x48)
    .maxstack  4
    .locals init (int32[] V_0,
             int32 V_1,
             int32 V_2)
    IL_0000:  ldc.i4.5
    IL_0001:  newarr     [mscorlib]System.Int32
    IL_0006:  stloc.0
    IL_0007:  ldc.i4.0
    IL_0008:  stloc.1
    IL_0009:  br.s       IL_0015

    IL_000b:  ldloc.0
    IL_000c:  ldloc.1
    IL_000d:  ldloc.1
    IL_000e:  ldloc.1
    IL_000f:  mul
    IL_0010:  stelem.i4
    IL_0011:  ldloc.1
    IL_0012:  ldc.i4.1
    IL_0013:  add
    IL_0014:  stloc.1
    IL_0015:  ldloc.1
    IL_0016:  ldloc.0
    IL_0017:  ldlen
    IL_0018:  conv.i4
    IL_0019:  blt.s      IL_000b

    IL_001b:  ldc.i4.0
    IL_001c:  stloc.2
    IL_001d:  br.s       IL_003b

    IL_001f:  ldstr      "arr[{0}]={1}"
    IL_0024:  ldloc.2
    IL_0025:  box        [mscorlib]System.Int32
    IL_002a:  ldloc.0
    IL_002b:  ldloc.2
    IL_002c:  ldelem.i4
    IL_002d:  box        [mscorlib]System.Int32
    IL_0032:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                  object,
                                                                  object)
    IL_0037:  ldloc.2
    IL_0038:  ldc.i4.1
    IL_0039:  add
    IL_003a:  stloc.2
    IL_003b:  ldloc.2
    IL_003c:  ldloc.0
    IL_003d:  ldlen
    IL_003e:  conv.i4
    IL_003f:  blt.s      IL_001f

    IL_0041:  call       int32 [mscorlib]System.Console::Read()
    IL_0046:  pop
    IL_0047:  ret
  } // end of method Test::Main

  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // 代码大小       7 (0x7)
    .maxstack  1
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method Test::.ctor

} // end of class Test


// =============================================================

//*********** 反汇编完成 ***********************
// WARNING: Created Win32 resource file Class2.res

我们粗略的感受是它很类似于早先的汇编语言,但它具有了对象定义和操作的功能。我们可以看到它定义并实现了一个继承自System.Object 的HelloWorld类及两个函数:Main()和.ctor()。其中.ctor()是HelloWorld类的构造函数,可在"HelloWorld.cs"源代码中我们并没有定义构造函数呀--是的,我们没有定义构造函数,但C#的编译器为我们添加了它。你还可以看到C#编译器也强制HelloWorld类继承System.Object类,虽然这个我们也没有指定。关于这些高级话题我们将在以后的讲座中予以剖析。

那么PE文件是怎么执行的呢?下面是一个典型的C#/.NET应用程序的执行过程:

  1. 用户执行编译器输出的应用程序(PE文件),操作系统载入PE文件,以及其他的DLL(.NET动态连接库)。
  2. 操作系统装载器根据前面PE文件中的可执行文件头跳转到程序的入口点。显然,操作系统并不能执行中间语言,该入口点也被设计为跳转到mscoree.dll(.NET平台的核心支持DLL)的_ CorExeMain()函数入口。
  3. CorExeMain()函数开始执行PE文件中的中间语言代码。这里的执行的意思是通用语言运行时按照调用的对象方法为单位,用即时编译器将中间语言编译成本地机二进制代码,执行并根据需要存于机器缓存。
  4. 程序的执行过程中,垃圾收集器负责内存的分配,释放等管理功能。
  5. 程序执行完毕,操作系统卸载应用程序。

 原文地址:http://www.microsoft.com/china/msdn/Archives/cornyfield/cornyfield.asp

问题10

Console.WriteLine()中{N}的含义

解决方案

using System;

public class Test
{
 static void Main()
 {
  int[] arr = new int[5];
  for(int i = 0;i < arr.Length;i++)
  {
   arr[i] = i * i;
  }
  for(int i = 0;i < arr.Length;i++)
  {
   Console.WriteLine("arr[{0}]={1}",i,arr[i]);
   
  }
  Console.Read();
 }
}
在Console.WriteLine("arr[{0}]={1}",i,arr[i]);第一个参数是“格式化”,后面的参数是填充到格式中的参数。
如:{0}填充i,{1}填充arr[i]。最后的结果为:"arr[i]="arr[i]。依次类推。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值