简介
本文教IL汇编语言可用于调试。NET代码的基础知识(在任何书面NET高级语言)处于较低水平。由低层次,我的意思是高级语言的编译器已经完成了他的工作点。此外,使用这些基本知识,你可以计划一个新的。NET语言编写您自己的编译器。内容的表{A}
{A9}{A10}{A11}{A12}{A13}{A14}{A15}{A16}
每当你编译你的代码。NET中,无论您选择的语言,它会转换为中间语言(IL),也称为Microsoft中间语言或共同的中间语言。你可以认为IL,Java语言所产生的字节码。如果你有兴趣了解如何。NET数据类型的处理,以及如何你写的代码转换成IL代码等,那么知识的IL会给你带来很大的优势。这些优势可能包括了解什么代码。NET编译器发出。因此,如果你知道的IL,那么你可以检查由编译器产生的代码,并作出必要的修改(虽然不是在大多数情况下需要)。您可以更改的IL代码,作出必要的修改(您的高层次语言可能不允许),增加你的表现代码。这也可以帮助你调试你的代码处于较低水平。此外,如果你打算写。NET编译器,那么它是必要的了解IL。
IL本身是二进制格式,这意味着它不能被人类阅读。但正如其他二进制文件(可执行文件)代码汇编语言,所以也有同样的方式IL汇编语言被称为IL大会(ILASM)。白细胞介素大会以同样的方式,为机汇编语言指令。一样,你有add指令,将两个数字相加,减去两个数字,你有SUB指令等,这是明显的。NET运行时(JIT)不能执行ILASM直接。如果你写一些代码,然后在ILASM首先你要编译,JIT将IL代码,然后运行此IL代码。
注意:请注意,白细胞介素和白细胞介素大会是两回事。每当我们谈论有关白细胞介素,那么它意味着二进制代码。NET编译器而ILASM的发射,将参照这是不以二进制形式的IL汇编语言。
注意:请注意,我期待,你都非常熟悉NET(包括任何高级语言)。。在这篇文章中,我不会去到一切细节,但只有那些我认为这是需要加以解释。如果有什么迷惑你,然后你可以联系我进行更多的讨论。IL汇编语言简介
现在让我们开始这篇文章的主要目的,引进IL汇编。 ILASM机汇编语言相同指令。你可以写在任何文本编辑器如记事本代码为ILASM,然后可以使用命令行编译器程序(Ilasm.exe)。NET框架提供的编译。 ILASM是一个艰难的工作,曾工作在高级语言,但C或C程序员可以很容易通过这些程序员。它,AOS一项艰巨的任务,那么我们不应该,AOT浪费我们的时间。在IL大会,我们必须手工做所有的事情,想推到堆栈的值,内存管理等认为ILASM相同但汇编语言,汇编语言处理与本地的Windows可执行文件和本次大会(ILASM)处理的。NET可执行文件和也,本次大会是更容易一点,以及面向对象的。
因此,让AOS这种语言年初开始我们的第一个例子程序将打印在屏幕上(控制台)的单一短语。这是一个传统,每一种语言的开始,所以我们会做同样的一个Hello World程序,但是这句话是改变。//Test.IL
//A simple programme which prints a string on the console
.assembly extern mscorlib {}
.assembly Test
{
.ver 1:0:1:0
}
.module test.exe
.method static void main() cil managed
{
.maxstack 1
.entrypoint
ldstr "I am from the IL Assembly Language..."
call void [mscorlib]System.Console::WriteLine (string)
ret
}
图1.1中ILASM的抽样检验方案
一个简单的文本编辑器如记事本写在上面的代码(图1.1),并保存为Test.il.现在,让我们先编译并运行此代码,然后我们会进入这个细节。要编译的代码,在命令提示符下键入{C}
{S0}
图1.2样品测试程序的输出。你可以看到我用的命令来编译代码。
ILAsm.exe是一个命令行工具,NET框架附带,可以在LT位于; windowsfoldergt; \ Microsoft.NET \框架\ LT; versiongt;文件夹。你可以在你的PATH环境变量包括这条道路。当你完成编译,IL文件,然后它将输出。IL文件的名称相同的EXE。您可以指定输出文件的名称,使用/输出= LT; filenamegt;像ILASM开关Test.il /输出= MyFile.exe。运行输出的exe文件,只需键入名称的EXE和回车。将之前在屏幕上输出。现在,让我们需要一些时间来了解我们编写的代码。记住,我指的是图1.1描述code.lt; / filenamegt; versiongt; LT / windowsfoldergt;前两行(/ /开始)的意见。 ILASM,你可以在同样的方法在C#或C发表评论。注释多行或线的一部分,您还可以使用/ * ... ... * /块。下一步,我们指示ILASM导入名为MSCORLIB(大会外部mscorlib程序{})库。 ILASM,每个语句开始一个时期的标志()。表明,该声明是一个特殊的指令(或指令)。所以,。大会指令这里说,我们要使用一个外部库(那不是我们写的这段代码,但预编译)。下一步。大会指令定义了我们的文件集的信息(组装测试....).在上面的例子中,我们提供的quot; Testquot;大会的名称和括号内,我们提供了一些有关输出程序集的信息。也就是说,版本信息。我们可以提供更多的信息,如在此块组装公钥等下一步指令告诉我们大会的模块名称(模块TEST.EXE)。我们知道,必须有至少一个模块,在每个程序集。移动到下一个(。方法的静态无效的主要(管理)CIL),方法指令标志,我们要定义一个方法,它是一个静态(一样在C#中的static关键字),并且没有返回值(无效)。此外,该方法的名称是主要的,它没有参数(括号内)。最后CIL管理指示编译器来编译为托管代码。移动里面的方法,第一个指令是maxstack(maxstack 1)。这是一件重要的事情宣布的最大数量的项目,我们将加载在内存(评价堆栈实际上)。稍后我们将讨论这个细节。如果你没有意识到这一点,然后跳到它的那一刻。。入口点指令告诉编译器标记为这种方法的应用程序,也就是从哪里开始执行的第一个函数程序的入口点。接下来的语句(ldstr"我从IL汇编语言...???, ldstr指令用于加载到内存或评估堆叠一个字符串,它是必要的值在此之前,可以利用加载到评估堆叠。我们将讨论详细的评价堆栈很快。Next语句(调用无效[0] System.Console:mscorlib程序库所在的WriteLine(字符串))呼叫(调用)一个方法。请注意,我们已向该方法的签名,包括返回类型,参数类型和库驻留。我们已把它作为参数,这是不是一个变量,而是一个数据类型的字符串。前面的语句(ldstr,AUI上午从IL ???.???/代码)加载字符串堆栈,这个方法是使用相同的字符串打印。最后声明,RET,虽然并不需要解释,指示从方法返回。
通过阅读上面的行,您可能有一个想法,如何ILASM语言编写的代码。你可能有一些想法,ILASM是不喜欢高层次的。NET语言(VB,C#中)。无论如何,你写的代码,你必须遵循这种结构(或变化不大,带班工作时)。现在有几件事情需要更多的讨论。主要评估堆叠,让我们做,第一。评估堆叠
评估堆叠,可视为正常的机器栈,堆栈用于存储信息前一个语句的执行。我们知道的信息是存储在内存中,当我们要执行对他们的一些操作。随着我们在汇编语言中值寄存器,然后调用一些指令/中断相同。我们必须以同样的方式处理前移动堆栈的信息(在我们上面的例子字符串)(输出到屏幕在上述情况下)。在我们的主要方法(图1.1)开始,我们通知了运行时。NET,我们需要一些信息存储在我们的方法的过程中。我们说,我们将在同一时间只有一个值移动堆栈使用maxstack指令。因此,如果我们写我们的指令。maxstack 3,然后运行时将创建一个堆栈中的三个值,我们可以在任何时候使用空间。请注意,它并不意味着我们可以加载摞在了我们的方法生活中只有三个值,但它意味着,我们可以一次移动最大的三个值。由于值从堆栈中移除处理完成。还应当注意到函数被调用时(调用),在函数中使用的值从堆栈和堆栈空间被清空删除。这是垃圾收集器。NET中如何。此外,没有任何限制,我们可以将某些类型的数据堆栈。栈在任何时间,我们可以将任何类型的数据(如字符串,整数,对象等)。
让我们看看另一个例子,这将明确评估堆叠的概念,我们。//Add.il
//Add Two Numbers
.assembly extern mscorlib {}
.assembly Add
{
.ver 1:0:1:0
}
.module add.exe
.method static void main() cil managed
{
.maxstack 2
.entrypoint
ldstr "The sum of 50 and 30 is = "
call void [mscorlib]System.Console::Write (string)
ldc.i4.s 50
ldc.i4 30
add
call void [mscorlib]System.Console::Write (int32)
ret
}
图1.3 Add.il添加两个预定义的号码。
以上部分的主要方法是我们的第一个例子相同。只有模块的名称已被更改。讨论的事情。maxstack指示运行时在内存分配足够的空间,我们可以节省两个值的主要方法。然后我们加载堆栈中的一个字符串,并印说出来。下一步,我们在内存中加载两个整数的同时使用ldc.i4.s和ldc.i4指示,并发出添加语句,最后打印一个整数类型的值。添加语句将看堆栈上的两个值,如果发现,将它们添加和存储堆栈的顶部。后添加语句,有所谓写的另一种方法,在控制台上写的东西。这种方法需要存储在堆栈的顶部,必须有一定的价值。在这种情况下,它会寻找整数类型。如果它开创整数值,那么它将打印,其他明智的,它会引发一个错误。
不要混淆ldc.i4.s和ldc.i4,双方代表的整数数据类型,但第一个单字节和第二个四字节。
我希望你已经明白了使用评估堆叠的方式,也认为它是如何工作的。现在让我们讨论有关的ILASM语言更多的东西。白细胞介素的数据类型
至于学习任何一种语言,我们首先讨论在该语言中使用的数据类型。因此,相同的情况下就在这里。让我们就看看下面的表(图1.4),以了解IL汇编的数据类型。但是,之前,我想点一件事,没有一致性。NET数据类型定义在不同的语言。像在VB中的整数(32位),NET是指使用整数,但在C#和VC,它是int;虽然在这两种情况下,它是代表System.Int32的。同时,我们必须要记住,是通用语言规范(CLS)符合或不。像不认可的VB。NET,也实在是不符合CLS UInt32的。
好,让我们开始记住ILASM语言的数据类型提供了新的名称表。白细胞介素名NET基类型的含义符合CLS
没有数据,仅用于返回类型
否
BOOL
System.Boolean
布尔值
否
字符
System.Char
字符值(16位Unicode)
否
INT8
System.SByte
单字节的整数(签名)
否
的Int16
System.Int16
两个字节的整数(签名)
否
INT32
System.Int32的
四字节整数(签名)
是
INT64
System.64
8字节整数(签名)
是
原生INT
System.IntPtr
符号整数
是
无符号INT8
System.Byte
一个字节的整数(无符号)
否
无符号的Int16
System.UInt16
两个字节的整数(无符号)
否
无符号INT32
System.UInt32
Fournbsp;字节的整数(无符号)
否
无符号INT64
System.UInt64
Eightnbsp;字节的整数(无符号)
是
本地unsigned int类型
System.UIntPtr
无符号整数
是
Float32
System.Single
四字节浮点
否
Float64
System.Double
Eightnbsp字节浮点
否
对象
System.Object的
对象类型的值
是
放大器;
托管指针
是
*
System.IntPtr
非托管指针
是
的typedef
System.Typed参考
特殊类型,保存数据和explicitlynbsp;表示的数据类型。
是
阵列
的System.Array
阵列
是
字符串
System.String
String类型
是
图1.4在ILASM的数据类型
我们也有ILASM的数据类型的一些助记符,如I4,。i4.s,U4等,因为我们在上面的例子中使用。上面列出的类型是由ILASM认可,也表提到,这类型符合CLS,哪些不的。所以,牢记上述类型,我们可以调用任何这样的功能call int32 SomeFunction (string, int32, float64<code lang=msil>)
这意味着,功能SomeFunction返回值类型INT32(System.Int32的),并分别采取三个值类型为string(System.String),INT32(System.Int32的)和float64(System.Double)。请注意,这些都是基本数据类型的CLR和ILASM。如果我们有兴趣处理的基本数据类型(用户定义),那么我们可以这样处理。//In C#
ColorTranslator.FromHtml(htmlColor)
//In ILAsm
call instance string [System.Drawing]
System.Drawing.ColorTranslator::ToHtml(valuetype
[System.Drawing]System.Drawing.Color)
注意,我们明确定义的参数类型。我们也该类型的居住和关键字的值类型的标志,我们引用任何非基本数据类型定义的命名空间。
的事情会在未来的一节更清晰的时候,我们将写一个示例程序将处理类型。但首先,让我们看看像变量声明,循环,条件等语言的基础知识变量声明
变量与任何编程语言的重要组成部分,因此,ILASM也为我们提供了一个声明和使用变量的方式。虽然不是那么简单,在更高的语言(VB。NET,C#中)。当地人指令可以被用来声明变量。开始的任何方法,虽然在任何地方,你可以把你的宣言,但很明显,在使用它们之前,这个指令通常应该发生。下面是一个示例,可以声明变量,设置的值,然后使用它们来打印。.locals init (int32, string)
ldc.i4 34
stloc.0
ldstr "Some Text for Local Variable"
stloc.1
ldloc.0
call void [mscorlib]System.Console::WriteLine(int32)
ldloc.1
call void [mscorlib]System.Console::WriteLine(string)
图1.5局部变量
我们声明两个变量使用。当地人指令,类型INT32和其他的字符串。然后我们加载一个类型的Int32值34内存和分配的局部变量为零,这是第一个变量实际上。注意ILASM变量的变量,可以通过其索引访问(定义),这些数字与零开始。然后我们加载到内存中的字符串并分配到第二个变量。最后,我们印这两个变量。 ldloc。可以用来装载任何类型的变量的值到内存(无论是整数,双浮动或对象)。
我没有使用的变量名。由于这些地方和我们不打算暴露出来的方法。不过,这并不意味着你不能声明变量名。当然,你可以。声明局部变量,你可以与它们的数据类型的变量名称,就像在C#。当地人喜欢的init(X,INT32 INT32 Ÿ)
后,您可以加载或设置这些变量使用相同的语句的值,但与像stloc X和ldloc Y.变量名虽然你已经声明您使用名称的变量,但您仍然可以存取他们与他们的人数像ldloc.0,stloc.0等注:整个本文中的代码,我使用没有名字的变量。
现在你的想法来处理变量和堆栈。如果您遇到任何问题,审查上面提供的代码,因为在现在,我们将有一些艰难的任务,当演奏与堆栈。我们会经常移动数据到内存中,并取回。因此,一个良好的初始化变量,设置变量的值和装载值堆栈变量的理解是必要的。决定/
决定或条件是其他任何编程语言的必要的对象。在低层次的语言,如本地的汇编语言,决定是使用跳跃(或分公司)。因此,同样是与ILASM。以看看下面的代码片段。br JumpOver //Or use the br.s instead of br
//Other code here which will be skipped after getting br statement.
//
JumpOver:
//The statements here will be executed
控制转移到goto语句后写了一些标签的任何高级语言编写的goto语句比较本声明。但在这里,BR是用来代替goto的。如果您确定的目标是在-128到127字节的BR声明,因为它会使用INT8分支偏移,而不是Int32的,也可用于br.s。因为有BR声明和代码前评估没有条件总是会跳/分支的JumpOver标签,上面的方法是无条件的分支。让我们来看看一个代码片段,可以描述使用条件分支手段,通过一些逻辑测试(或分支)的跳跃。 //Branching.il
.method static void main() cil managed
{
.maxstack 2
.entrypoint
//Takes First values from the User
ldstr "Enter First Number"
call void [mscorlib]System.Console::WriteLine (string)
call string [mscorlib]System.Console::ReadLine ()
call int32 [mscorlib]System.Int32::Parse(string)
//Takes Second values from the User
ldstr "Enter Second Number"
call void [mscorlib]System.Console::WriteLine (string)
call string [mscorlib]System.Console::ReadLine ()
call int32 [mscorlib]System.Int32::Parse(string
)
ble Smaller
ldstr "Second Number is smaller than first."
call void [mscorlib]System.Console::WriteLine (string)
br Exit
Smaller:
ldstr "First number is smaller than second."
call void [mscorlib]System.Console::WriteLine (string)
Exit:
ret
}
图1.6 Branching.il(只有main方法,包括)
上面的程序需要从用户的两个值,然后检查较小的数字。声明需要注意的是,Äúble小??指示编译器检查堆栈中的第一个值小于或等于第二个,那么就应该转移到更小的标签。 ,如果它不是那么没有分支将发生的下一个语句将被执行,这是加载一个字符串,然后打印,出。在此之后,一个无条件分支发生,这是必要的,因为如果不在这里再根据程序流,较小的标签后的语句会被执行。所以,我们发出的,Äúbr退出??导致程序分支到出口标签和执行RET语句。
其他条件包括BEQ (==), BNE,BGE(GT =)(=!),BGT(GT),BLE(LT),BLT(LT),并brfalse(如果顶部的项目在堆栈是零)和brtrue(如果堆栈顶部的项目不为零)。您可以使用任何执行你的代码的某些部分,并跳过其他。正如我刚才所说,有没有ILASM正如我们在高级语言中的设施。所以一切都应该做自己,如果你仍然打算写一些代码在ILASM。
循环
另一种语言的基础知识部分的循环。循环只不过是一次又一次的重复相同的代码块。它涉及的分支实际上取决于一个变量的循环索引值。同样,你要看看代码,并花一点时间来了解如何循环工作。 .method static void main() cil managed
{
//Define two local
variables .locals init (int32, int32)
.maxstack 2
.entrypoint
ldc.i4 4
stloc.0 //Upper limit of the Loop, total 5
ldc.i4 0
stloc.1 //Initialize the Starting of loop
Start:
//Check if the Counter exceeds
ldloc.1
ldloc.0
bgt Exit //If Second variable exceeds the first variable, then exit
ldloc.1
call void [mscorlib]System.Console::WriteLine(int32)
//Increase the Counter
ldc.i4 1
ldloc.1
add
stloc.1
br Start
Exit:
ret
}
图1.7 Loops.il(只有main方法)
虽然相同的代码可以在更高的语言编写的,如C#,,看起来应该像这样for (temp=0; temp <5; temp++)
System.Console.WriteLine (temp)
让我们来看看代码。首先,我们声明了两个局部变量和初始化值4和第二个变量与零的第一个变量。真正的循环开始从"开始"标签,从其中,我们首先检查循环计数器(变量2,ldloc 1)超过上限循环(变量1,ldloc 0),如果是这样的话,那么程序将跳转到退出标签,这将导致终止程序。如果是这种情况并非如此,那么该值将被打印在屏幕上,一个增量将在变量和代码,会跳,再次开始标签进行检查,如果计数器超过上限或不。这是循环ILASM工程。定义方法
我们已经看到了有关的决定(条件或分支),循环,也宣告变量。现在是时候看到的方法,如何能在ILASM创建。声明方法ILASM的方法几乎是相同的的,我希望您能猜到到现在,在C#或C,但有一点变化。所以,让我们的代码片段,然后我们将讨论我们所做的。//Methods.il
//Creating Methods
.assembly extern mscorlib {}
.assembly Methods
{
.ver 1:0:1:0
}
.module Methods.exe
.method static void main() cil managed
{
.maxstack 2
.entrypoint
ldc.i4 10
ldc.i4 20
call int32 DoSum(int32, int32)
call void PrintSum(int32)
ret
}
.method public static int32 DoSum (int32 , int32 ) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
add
ret
}
.method public static void PrintSum(int32) cil managed
{
.maxstack 2
ldstr "The Result is : "
call void [mscorlib]System.Console::Write(string)
ldarg.0
call void [mscorlib]System.Console::Write(int32)
ret
}
图1.7 Methods.il定义和调用自己的方法
一个简单的程序,它增加了两个数字(预先定义为了简单的代码,),并打印出结果。在这里我们定义了两个方法。请注意,这两种方法都是静态的,使我们可以直接使用,而无需创建任何实例。首先,我们加载在栈上的两个数字,并期待在栈上的两个Int32值称为第一种方法DoSum。函数体,声明如下主要的相同,我们已经看到了很多次,到现在为止,我们再次明确的maxstack但要注意,我们没有因为一个程序可以包含入口点指令只有一个切入点,并在上面的例子中,我们已宣布的主要方法为切入点。 ldarg.0 ldarg.1指示运行时加载评估堆叠上的参数,参数传递给该方法。然后,我们只是简单地添加使用添加语句,然后方法返回。请注意,该方法返回一个值的Int32类型。现在它应该返回的值?当然,堆栈添加语句时完成其工作的价值。从这里的控制将被调回的主要方法,它会调用另一个方法PrintSum。 PrintSum还需要一个INT32类型的值。现在应该指出,DoSum方法返回的Int32类型值,并在评估堆叠,同时,我们称为PrintSum的方法,这也是为寻找一个Int32类型的值。因此,从DoSum方法的返回值将被传递到PrintSum PrintSum,它首先在屏幕上打印一个简单的字符串,然后加载的参数使用ldarg.0,然后打印,太。
上面的方法,创造方法是不是一个艰巨的任务在ILASM。是的,实际上它是。但是,方法得到参考值。因此,让AOS采取一看。
通过引用传递变量
IL还支持参考值,当然应该,因为高级语言。NET中的参考参数和高级语言代码支持转换为IL代码和我们所讨论的IL汇编语言产生相同的IL代码。每当我们通过引用传递的任何变量,那么,该变量的值存储的内存地址,通过对比值的方法,在传递给函数的值的副本。让我们来看看如何通过参考方法在IL汇编作品的一个例子。.method static void main() cil managed
{
.maxstack 2
.entrypoint
.locals init (int32, int32)
ldc.i4 10
stloc.0
ldc.i4 20
stloc.1
ldloca 0 //Loads the address of first local variable
ldloc.1 //Loads the value of Second Local Variable
call void DoSum(int32 &, int32 )
ldloc.0
//Load First variable again, but value this time, not address
call void [mscorlib]System.Console::WriteLine(int32)
ret
}
.method public static void DoSum (int32 &, int32 ) cil managed
{
.maxstack 2
.locals init (int32)
//Resolve the address, and copy value to local variable
ldarg.0
ldind.i4
stloc.0
ldloc.0
//Perform the Sum
ldarg.1
add
stloc.0
ldarg.0
ldloc.0
stind.i4
ret
}
图1.8 MethodRef.il通过引用传递变量。
在上面的例子有趣的事情是对像ldloca,它加载的变量的地址的一些新的指令,而不是堆栈中的价值,的使用。在main方法中,我们宣布了两个变量(本地)和分配给他们一些值(分别为10和20)。然后我们加载的第一个变量的地址,第二个变量的内存和价值,并调用DoSum方法。如果你看到DoSome的方法签名(调用),那么你会发现一件事,我们用放大器;第一INT32(参数),其中提到,堆栈包含内存引用,而不是价值,我们有兴趣通过引用变量。以同样的方式,DoSome方法声明也包含着同样的放大器,第一个参数,它接收这也肯定就更不用说了,说,该变量将通过引用传递。所以,一个变量是通过参考价值的第二个(正常)。现在的问题是解决地址的价值,使我们可以执行一些行动上的价值,然后设置如果有必要的变量。出于这个原因,我们第一个参数加载到堆栈(其中包含实际变量的地址传递)和调用ldind.i4声明载入一个整数(32位)的值从堆栈地址(进入该地址,读取值放在堆栈上)。我们存储在一个局部变量的值,使我们可以重复使用,很容易(或我们要一次又一次地执行这些步骤)。然后,简单地说,我们加载到堆栈,局部变量,第二个参数(按值),并将它们添加并存储在同一个本地变量。现在有一个更有趣的事情,在这里,我们改变了价值上的内存位置,这是代表第一个参数的值(按引用传递的参数)。我们没有,第一次加载参数0(引用参数)堆栈,这实际上是将负载传递给这个方法的原始变量的地址,那么我们的价值要设置,最后的声明,stind.i4这是对面ldind.i4声明,我们上面使用。它设置的对堆栈的内存位置的值。为了测试改变的值,我们简单地印的主要方法。请注意DoSum方法不返回任何东西,并且的主要方法,我们只需载入第一个局部变量(现值,而不是内存引用)和使用WriteLine方法来打印。
这是ILASM与引用变量的处理方式。到了这里,我们所看到的变量声明,条件,循环和方法(由值参数和引用参数)打球的方法。现在是时候宣布我们的命名空间和类使用ILASM语言。创建命名空间和类
是的,当然,它有可能在ILASM创建类和命名空间。其实,这是相当容易的创建类或命名空间中ILASM的任何更高层次的语言。不信?然后让我们来看看。//Classes.il
//Creating
Classes
.assembly extern
mscorlib {} .assembly Classes
{ .ver 1:0:1:0 }
.module Classes.exe
.namespace HangamaHouse
{
.class public ansi auto Myclass extends [mscorlib]System.Object
{
.method public static void main() cil managed
{
.maxstack 1
.entrypoint
ldstr "Hello World From HangamaHouse.MyClass::main()"
call void [mscorlib]System.Console::WriteLine(string)
ret
}
}
}
图1.9 Classes.il创建自己的命名空间和类。
我认为,现在还不是急需的解释代码。的东西很简单,namespace指令,名称HangamaHouse,发出来告诉编译器,我们要创建一个命名空间名称HangamaHouse。块的命名空间内,我们推出了一个新的类。类指令,并提到,这个类是公共从System.Object类的扩展(继承)。这个类只包含一个方法,该方法是静态的和公共的。其余的代码的方法,你很清楚。
在这里,我想提,所有类创建从Object类继承,如果你不提任何继承。在这种情况下一样,我们明确提到,我们的类继承System命名空间中的对象类,如果我们不提它这里,那么它仍然会继承Object类。是的,有一种情况,我们从任何其他类的类继承,那么它不会从Object类继承(但你继承你的类,类继承的对象类)。
有两个在上面的类创建中使用的关键字,这些都是ANSI和汽车。 ANSI告诉应类中的所有字符串转换为ANSI字符串。其他选项这是Unicode和autochar(根据平台的自动转换,将取决于)。第二个是自动关键字指定运行时会自动选择适当的布局在非托管内存中的对象的成员。这个选项顺序(成员依次)和明确的明确定义(布局)。有关更多信息,请参阅MSDN中StructLayout或LayoutKind枚举。汽车和ANSI类的默认关键字,如果你不定义任何东西,这将自动假设。对象范围(会员无障碍标志)
下表总结了ILASM类的范围。ILASM名称说明C#的名称
公共
可见的类,命名空间和对象(所有)
市民
私人
内同类产品中唯一可见
私人
家庭
类和派生类只可见
保护
大会
仅可见在同一集会
内部
familyandassem
在同一程序集的派生类可见
N / A
familyorassem
可见派生类和相同大会
受保护的内部
privatescope
,私营,但它不能被refereneced
N / A
图1.10 ILASM会员无障碍标志
有一些更多的可使用的方法和字段(类变量)的范围。你可以找到在MSDN的完整列表。创建和使用类对象
在我的文章的这一部分,我将显示你,你怎么能创建你的类,使用ILASM代码的实例。在此之前,你已经看到,如何创建自己的命名空间和类在ILASM。但创造的东西是没用的,直到我们不能使用。所以,让我们开始创建一个简单的类,并使用该。
让我们在ILASM创造我们自己的图书馆。这个简单的库只包含一个公共方法。也就是说,它会收到一个值,将返回该值的平方。简单是最好的了解。看看代码。.assembly extern mscorlib {}
.assembly MathLib
{
.ver 1:0:1:0
}
.module MathLib.dll
.namespace HangamaHouse
{
.class public ansi auto MathClass extends [mscorlib]System.Object
{
.method public int32 GetSquare(int32) cil managed
{
.maxstack 3
ldarg.0 //Load the Object's 'this' pointer on the stack
ldarg.1
ldarg.1
mul
ret
}
}
}
图1.11为数学运算广场MathLib.il图书馆
注意:上面的代码编译到一个DLL文件。使用ILASM MathLib.il / DLL
代码看起来简单。它定义了一个命名空间的名称HangamaHouse和该命名空间内,一类名为MathClass的,从System命名空间中的对象类的扩展,我们上面的类(图1.10)。现在,在这个类,我们定义一个命名GetSquare的方法需要一个参数类型的Int32。我们定义的maxstack至3,然后加载参数0。然后我们再装入一个参数两次。等一下,我们这里只接收一个参数,但我们已加载参数0和一个(共两个参数)。怎么可能呢?那么它是。其实,零参数(ldarg.0)是对象的引用,以quot; thisquot;指针。由于每个实例对象总是通过该对象的内存地址。所以我们的实际参数(S)从索引1开始。好吧,我们加载参数1两次,使我们可以将它们相乘,我们与MUL指令。乘法的结果存储在堆栈返回调用方法,因为我们RET指令立即发出。
库的建设是没有问题。简单但现在让我们来看看在使用这个库的例子.assembly extern mscorlib {}
.assembly extern MathLib {.ver 1:0:1:0}
//
//rest code here
//
.method static void Main() cil managed
{
.maxstack 2
.entrypoint
.locals init (valuetype [MathLib]HangamaHouse.MathClass mclass)
ldloca mclass
ldc.i4 5
call instance int32 [MathLib]HangamaHouse.MathClass::GetSquare(int32)
ldstr "The Square of 5 Returned : "
call void [mscorlib]System.Console::Write(string)
call void [mscorlib]System.Console::WriteLine(int32)
ret
}
图1.12使用mathlib中库的类MathClass的
首先两行这种方法很简单。请注意,我们有进口与mscorlib程序库库(mathlib中),我们还提供了版本号,这是,虽然没有必要,因为我们已经来到第三行,我们定义一个类型MathClass的的局部变量(从HangamaHouse命名空间。.class public MathClass extends [mscorlib]System.ValueType
{
.field private int32 mValue
//Other code goes here
.method public specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
ldc.i4.s 15
stfld int32 HangamaHouse.MathClass::mValue
ret
}
//Other code goes here.
.method public static void Main() cil managed
{
.maxstack 2
.entrypoint
.locals init (valuetype [MathLib]HangamaHouse.MathClass mclass)
ldloca mclass
call instance void [MathLib]HangamaHouse.MathClass::.ctor()
.method specialname public instance int32 get_Value() cil managed
{
ldarg.0
ldfld int32 HangamaHouse.MathClass::mValue
ret
}
.method specialname public instance void set_Value(int32 ) cil managed
{
ldarg.0
ldarg.1
stfld int32 HangamaHouse.MathClass::mValue
ret
}
//Define the property, Value
.property int32 Value()
{
.get instance int32 get_Value()
.set instance void set_Value(int32 )
}
.maxstack 2 .locals
init (valuetype [MathLib]HangamaHouse.MathClass tclass)
ldloca tclass
ldc.i4 25
call instance void [MathLib]HangamaHouse.MathClass::set_Value(int32)
ldloca tclass
call instance int32 [MathLib]HangamaHouse.MathClass::get_Value()
ldstr "Propert Value Set to : "
call void [mscorlib]System.Console::Write(string)
call void [mscorlib]System.Console::WriteLine(int32)
.namespace MyForm
{
.class public TestForm extends
[System.Windows.Forms]System.Windows.Forms.Form
{
.field private class [System]System.ComponentModel.IContainer components
.method public static void Main() cil managed
{
.entrypoint
.maxstack 1
//Create New Object of TestForm Class and Call the Constructor
newobj instance void MyForm.TestForm::.ctor()
call void [System.Windows.Forms]
System.Windows.Forms.Application::Run(
class [System.Windows.Forms]System.Windows.Forms.Form)
ret
}
.method public specialname rtspecialname instance
void .ctor() cil managed
{
.maxstack 4
ldarg.0
//Call Base Class Constructor
call instance void [System.Windows.Forms]
System.Windows.Forms.Form::.ctor()
//Initialize the Components
ldarg.0
newobj instance void [System]System.ComponentModel.Container::.ctor()
stfld class [System]System.ComponentModel.IContainer
MyForm.TestForm::components
//Set the Title of the Window (Form)
ldarg.0
ldstr "This is the Title of the Form...."
call instance void [System.Windows.Forms]
System.Windows.Forms.Control::set_Text(string)
//Set the Back Color of the Form
ldarg.0
ldc.i4 0xff
ldc.i4 0
ldc.i4 0
call valuetype [System.Drawing]System.Drawing.Color
[System.Drawing]System.Drawing.Color::FromArgb(
int32, int32, int32)
call instance void [System.Windows.Forms]
System.Windows.Forms.Control::set_BackColor(
valuetype [System.Drawing]System.Drawing.Color)
//Maximize the Form using WindowState Property
ldarg.0
ldc.i4 2 //2 for Maximize
call instance void [System.Windows.Forms]
System.Windows.Forms.Form::set_WindowState(
valuetype [System.Windows.Forms]
System.Windows.Forms.FormWindowState)
ret
}
.method family virtual instance void Dispose(bool disposing) cil managed
{
.maxstack 2
ldarg.0
ldfld class [System]System.ComponentModel.IContainer
MyForm.TestForm::components
callvirt instance void [mscorlib]System.IDisposable::Dispose()
//Call Base Class's Dispose Event
ldarg.0
ldarg.1
call instance void [System.Windows.Forms]
System.Windows.Forms.Form::Dispose(bool)
ret
}
ILAsm.exe Test.il /debug
peverify.exe Test.exe
摘要结论作者简介ILDasm.exe SomeProject.exe /out:SomeProject.il
感谢
160;
再次感谢。//In C#
ColorTranslator.FromHtml(htmlColor)
//In ILAsm
call instance string [System.Drawing]
System.Drawing.ColorTranslator::ToHtml(valuetype
[System.Drawing]System.Drawing.Color)
,
{
160; &
#160; }
{
&
#160;
; )
;
0;