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

NET探秘:MSIL权威指南 简单示例CLR 基础 CLR 是供 NET 应用程序使用的运行时环境 它在 NET 应用程序和底层操作系统之间提供了一个操作层 CLS 公共语言规范 限制了命名约定 数据类型 函数类型以及某些其他元素 为不同的语言提供了一个公共标准 在 CLR 环境下 NET 应用程序的抽象的中间表示包括了两个主要组件 元数据和托管代码

大家好,我是讯享网,很高兴认识大家。

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可以有任意数量任意类型的可选参数。

小讯
上一篇 2025-03-04 08:09
下一篇 2025-02-24 16:16

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/116270.html