NET探秘:MSIL权威指南 简单示例

CLR基础

CLR是供.NET应用程序使用的运行时环境,它在.NET应用程序和底层操作系统之间提供了一个操作层。

CLS公共语言规范,限制了命名约定、数据类型、函数类型以及某些其他元素,为不同的语言提供了一个公共标准。

在CLR环境下,.NET应用程序的抽象的中间表示包括了两个主要组件:元数据和托管代码。

元数据是应用程序的所有结构项(类、类的成员和特性、全局项等)的描述符以及它们的关系所组成的一套系统。托管代码表示了应用程序的方法(函数)的功能,它们以中间语言的抽象二进制形式进行编码,我们简称为IL。

简单示例

//---------程序头
.assembly extern mscorlib { }
.assembly OddOrEven { }
.module OddOrEven.exe

//---------类声明
.namespace Odd.or {
	.class public auto ansi Even extends [mscorlib]System.Object {
//---------字段声明
		.field public static int32 val
//---------方法声明
		.method public static void check() cil managed {
			.entrypoint
			.locals init (int32 Retval) //初始化局部变量Retval,如果有多个则用逗号分开,例如:init(int32 a,string b)
		AskForNumber:
			ldstr "Enter a number"
			call void [mscorlib]System.Console::WriteLine(string)
			call string [mscorlib]System.Console::ReadLine()
			ldsflda valuetype CharArray8 Format //载入valuetype CharArray8的静态字段Format的"地址",这个地址不是真实的地址或者说c/c++的指针,而是引用。IL有单独的指令载入实例和静态字段(ldfld和ldsfld)或他们的地址(ldflda和ldsflda)
			ldsflda int32 Odd.or.Even::val
			call vararg int32 sscanf(string,int8*,...,int32*)
			stloc Retval //从栈上获取sscanf的调用结果存储至局部变量Retval中
			ldloc Retval //将Retval压入栈
			brfalse Error //从栈顶取出一项,如果该项为0则跳转至Error标记
			ldsfld int32 Odd.or.Even::val
			ldc.i4 1
			and
			brfalse ItsEven
			ldstr "odd!" //加载字符串到栈上
			br PrintAndReturn
		ItsEven:
			ldstr "even!"
			br PrintAndReturn
		Error:
			ldstr "How rude!"
		PrintAndReturn:
			call void [mscorlib]System.Console::WriteLine(string)
			ldloc Retval
			brtrue AskForNumber
			ret
		}//方法结束
	}//类结束
}//命名空间结束

//全局项
.field public static valuetype CharArray8 Format at FormatData
//-------------数据声明
.data FormatData = bytearray(25 64 00 00 00 00 00 00) //%d
//--------------作为占位符的值类型
.class public explicit CharArray8 extends [mscorlib]System.ValueType {.size 8}
//--------------调用非托管方法
.method public static pinvokeimpl("msvcrt.dll" cdecl)
	vararg int32 sscanf(string,int8*) cil managed {}

程序头

//---------程序头
.assembly extern mscorlib { auto }
.assembly OddOrEven { }
.module OddOrEven.exe

.assembly extern mscorlib { auto } 定义了一个名为AssemblyRef的元素据项,它标识了这个程序中使用的外部托管应用程序(程序集)。在这里使用的是Mscorlib.dll,这是.NET Framework类库的主程序集。

.assembly OddOrEven {} 定义了一个名为Assembly(程序集)的元数据项。

.module OddOrEven.exe定义了一个名为Module(模块)的元数据项,它标识了当前的模块。

类声明

//---------类声明
.namespace Odd.or {
	.class public auto ansi Even extends [mscorlib]System.Object {
    ......
    }
}

.namesace Odd.or { ... } 声明了命名空间。

.class public  auto ansi Even extends [mscorlib]System.Object { ... } 定义了一个名为TypeDef(类型定义)的元数据项。

类的名称是Even。关键字public定义了类的可见性。auto定义了类的布局风格(自动布局,默认值),指出加载程序可以采用它认为合适的方式进行布局。ansi定义了类和其他非托管代码进行交互操作时,类中字符串转换的模式。

extends定义了类的父类。

字段声明

//---------字段声明
		.field public static int32 val

定义了一个名为FieldDef(字段定义)的元数据项。

public和static定义了FieldDef的标识。public标志了可访问性,static表示这个字段是静态的。

方法声明

//---------方法声明
		.method public static void check() cil managed {
			.entrypoint
			.locals init (int32 Retval) 
        ......
        }

定义了一个名为MethodDef(方法声明)的元数据项。

public和static定义了MethodDef的标识。

关键字void 定义了方法的返回类型。

cil和managed 定义了MethodDef中所谓的实现标识,指出了方法体是用IL表示的。使用本地代码而不是IL来表示的方法,会带有实现标志native unmanaged。

方法体通常包括三种项:指令、标注了指令的标号、伪指令。

.entrypoint将当前方法标识为应用程序(程序集)的入口点。

.locals init(int32 Retval)定义了当前方法的唯一一个局部变量。变量类型是int32 ,名称是Retval。

关键字init 表示这个局部变量将会在方法执行之前在运行期间被初始化。

AskForNumber:
			ldstr "Enter a number"
			call void [mscorlib]System.Console::WriteLine(string)

AskForNumber:是一个标号。标号不会被编译为元数据或IL,而只是在编译期间用于标识IL代码中特定的偏移量。

ldstr "Enter a number"这条指令从指定字符串常量创建了字符串对象,并把指向这个对象的引用载入到栈上。

call void [mscorlib]System.Console::WriteLine(string) 这条指令调用了.NET Framework类库的控制台输出方法。

            call string [mscorlib]System.Console::ReadLine()
			ldsflda valuetype CharArray8 Format 
			ldsflda int32 Odd.or.Even::val
			call vararg int32 sscanf(string,int8*,...,int32*)

call string [mscorlib]System.Console::ReadLine() 这条指令调用了.NET Framework类库的控制台输入方法。没有从栈上取出任何值,并把一个字符串作为这次调用的结果放到栈上。

ldsflda valuetype CharArray8 Format 将类型为valuetype CharArray8的静态字段Format的地址载入。

ldsflda int32 Odd.or.Even::val这条指令加载了静态字段val的地址。

call vararg int32 sscanf(string,int8*,...,int32*) 这条指令调用了全局静态方法sscanf。这个方法从当前栈上取出三个项(Readline返回的字符串、对全局字段Format的引用、对字段val的引用),并把结果放回到栈上。

stloc Retval //从栈上获取sscanf的调用结果存储至局部变量Retval中
ldloc Retval //将Retval压入栈
brfalse Error //从栈顶取出一项,如果该项为0则跳转至Error标记

ldsfld int32 Odd.or.Even::val
ldc.i4 1
and
brfalse ItsEven
ldstr "odd!" 
br PrintAndReturn

ldsfld int32 Odd.or.Even::val 将val的值加载到栈上。

ldc.i4 1这条指令将1加载到栈上。

指令and从栈上获取两个项,val和1,然后执行AND位操作并把结果放回到栈上。

brfalse ItsEven 从栈上获取一个项(AND位操作的结果),如果它是0,程序就会跳转到ItsEven这个标号上。如果val的值是偶数,那么前一个指令的结果就是0,否则就是1。

ldstr "odd!"这条指令将字符串"odd!"加载到栈上。

br PrintAndReturn这条指令触及不到栈,它会无条件跳转到PrintAndReturn标号上。

全局项

//全局项
.field public static valuetype CharArray8 Format at FormatData

声明了类型为valuetype CharArry8、名为Format的静态字段。

数据声明

//-------------数据声明
.data FormatData = bytearray(25 64 00 00 00 00 00 00) //%d

定义了带有符号FormatData的数据段。这个段有8字节的长度。这个数据段称为字节数组。

作为占位符的值类型

//--------------作为占位符的值类型
.class public explicit CharArray8 extends [mscorlib]System.ValueType {.size 8}

声明了没有成员的值类型,但是具有显式指定的大小——8个字节。声明这个值类型通常是为了声明“仅仅需要一块内存”。

调用非托管代码

//--------------调用非托管方法
.method public static pinvokeimpl("msvcrt.dll" cdecl)
    vararg int32 sscanf(string,int8*) cil managed {}

声明了一个非托管方法,它是从托管代码中调用的。特性pinvokeimpl("msvcrt.dll" cdecl)指出这是一个非托管方法,要使用P/Invoke(平台调用)的机制调用,它还指出这个方法驻留于Msbcrt.dll中,并拥有调用约定cdecl。

这个方法需要两个必须的参数,类型为string和int8*(char*),返回int32类型的值。

vararg指定sscanf可以有任意数量任意类型的可选参数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MSIL(Microsoft Intermediate Language)权威指南是一本关于MSIL的详细指南,它是用于.NET平台的中间语言。MSIL权威指南的PDF版本是一份便携式文档,可以在电脑或其他设备上方便地阅读。这本指南提供了关于MSIL语法、结构和操作码的全面介绍。 MSIL是一种与平台无关的字节码,它是在将源代码编译成可执行代码之前生成的。通过学习和理解MSIL,开发人员可以更好地理解.Net应用程序的内部运作机制。这对于开发高效、可靠和安全的应用程序是至关重要的。 在MSIL权威指南中,读者将了解到如何编写和调试MSIL代码,以及如何使用不同的工具来检查和分析MSIL指令。此外,该指南还介绍了如何使用反汇编器来查看已编译的代码,并通过示例代码和说明展示了许多常见的MSIL编程场景。 通过PDF格式,读者可以随时随地访问MSIL权威指南,无论是在写代码时需要参考,还是在学习和研究MSIL时需要深入研究。此外,PDF格式还方便读者在电子设备上进行搜索、书签和注释,以便更好地管理和使用这个权威指南。 总之,MSIL权威指南的PDF版本提供了一种方便、可靠且易于阅读的方式,使开发人员了解和掌握MSIL的核心概念和技术。无论是初学者还是有经验的开发人员,都可以从这本指南中获得宝贵的知识和技巧,以提升他们的开发技能和应用程序的质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值