IL 汇编学习笔记(二)

原文:http://www.codeproject.com/dotnet/ilassembly.asp

条件语句


先来看一个简单的跳转:

br JumpOver // 或用 br.s 代替 br
// 这里的其他代码会被跳过。。。
//
JumpOver:
    
// 这里的代码将被执行

br 的作用类似于高级语言的 goto 语句,如果你能确定 target 语句在 br 语句的 -128 到 127byte 范围内,则可以用 br.s 代替。因为 br.s 会使用 int8 而不是 int32 保存用于跳转的位移量。


有条件的跳转语句

 //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
}


这里 ble 表示如果堆栈中第一个值小于等于第二个,则跳转。
其他还有一些跳转条件:
    beq(==), bne(!=), bge(>=), bgt(>) ble(<=), blt(<)
    brfalse(栈顶元素为 0),
    brtrue(栈顶元素非 0)


循环

循环也是使用普通的分支语句来跳转,可以用一个 loop index 来判断循环的终止条件。
例子:

.method static void main() cil managed
{
    
// 定义两个局部变量
    .locals init (int32, int32)
    .maxstack 
2
    .entrypoint
    ldc.i4 
4    
    stloc.
0 // 变量0 = 4,循环的上限,total 5
    ldc.i4 0
    stloc.
1 // 变量1 = 0,计数器

Start:
    
// 判断计数器是否超出范围
    ldloc.1
    ldloc.
0
    bgt Exit

    ldloc.
1
    call 
void
    
// 打印出计数器的当前值
    [mscorlib]System.Console::WriteLine(int32)
    
    
// 增加计数器
    ldc.i4 1
    ldloc.
1
    add
    stloc.
1
    br Start
    
Exit:
    ret
}

    
用比较直观的方式翻译为 C# 代码,大致上相当于:
(注:这个代码是为了便于和 IL 对照,实际并非最简单的写法)

public static void Main()
{
    
int max, counter;
    max 
= 4;
    counter 
= 0;
    
while (true)
    {
        
if (counter > max)
            
break;
        Console.WriteLine(counter);
        counter
++;
    }    
}


如何创建方法

看代码:

//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
}


如何用引用的方式传参:

.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 // 加载变量0 的地址到 Evaluation Stack
    ldloc.1
    call 
void DoSum(int32 &, int32 )
    ldloc.
0
    
// 再次加载变量0, 这次是值而不是地址
    call void [mscorlib]System.Console::WriteLine(int32)
    ret
}
.method 
public static void DoSum (int32 &, int32 ) cil managed
{
    .maxstack 
2
    .locals init (int32)
    
// 加载地址,并把值复制到局部变量
    ldarg.0
    ldind.i4 
// 读取栈顶的地址,根据这个地址去读取一个 int 值,把值写到堆栈
    stloc.0  // 保存到局部变量
    ldloc.0
    
// 做加法
    ldarg.1
    add
    stloc.
0

    ldarg.
0
    ldloc.
0
    stind.i4 
// 设定一个内存地址为整形值。op1: 地址,op2: 值
    
    ret
}


创建类和名称空间

//Classes.il
//Creating
Classes
.assembly 
extern

mscorlib {} .assembly Classes

{ .ver 
1:0:1:0    }
.module Classes.exe
.
namespace HangamaHouse

{
    
// ansi 表示该类中每一个字符串都要被转换为 ANSI 字符串。可选的其他值有:unicode, autochar
    
// auto 表示运行时会在非托管的内存中,为该类的成员自动选择合适的内存布局(layout). 可选的其他值有:sequential(顺序布局),explicit(严格定义)。详细参考 msdn 里的 StructLayout 或 LayoutKind 枚举
    
//
    
// 不指定的情况下,auto 和 ansi 是默认值。
    .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
        
        }
    }    
}

在 ILAsm 中,类可以有如下的访问级别修饰符

ILAsm Name

Description

C# Name

Public

visible to class, namespace and objects (all)

public

Private

visible inside the class only

private

Family

visible to class and derived classes only

protected

assembly

visible within same assembly only

internal

familyandassem

visible within derived classes of the same assembly

N/A

familyorassem

visible to derived classes and those of the same assembly

protectedinternal

privatescope

as that the private, but it can not be refereneced

N/A


对于类的方法和字段,可以有更多的修饰符,详见 MSDN.


(To be continued)

posted on 2006-04-04 17:35  NeilChen  阅读(966)  评论(0编辑  收藏  举报

导航