CIL之——field的存储与加载

field指的是类内部的成员变量,供类内部的方法调用,那在CIL代码中field是如何实现存储与加载的呢?下面让我们一窥究竟。

目标C#代码

先看一段简单的C#代码:

public class Program
{
    // Fields
    private string _timeArea;

    // Methods
    public string get_TimeArea()
    {
        // This item is obfuscated and can not be translated.
        return this._timeArea;
    }

    public static void Main()
    {
        // This item is obfuscated and can not be translated.
        Console.WriteLine("Hello");
    }

    public void set_TimeArea(string value)
    {
        // This item is obfuscated and can not be translated.
        this._timeArea = value;
    }
}

CIL实现field存储

例一:

.class public Program extends [mscorlib]System.Object
{
    .field private string _timeArea
    .method public static void Main()
    {
        .entrypoint
        .maxstack 1
        ldstr "Hello"
        call void [mscorlib]System.Console::WriteLine(string)
        call string [mscorlib]System.Console::ReadLine()
        ret
    }
    .method public void set_TimeArea(string 'value')//(string val)不用加单引号
    {
        .maxstack 1
        ldarg.0 //本操作码对应this._timeArea=value中的this
        ldarg.1 //本操作码对应this._timeArea=value中的value
        stfld string GuoNameSpace.Program::_timeArea //本操作码对应this._timeArea=value中的._timeArea
        ret
    }
}

例一解释:

public class Program
{
    // Fields
    private string _timeArea;

    public static void Main()
    {
        // This item is obfuscated and can not be translated.
        Console.WriteLine("Hello");
    }

    public void set_TimeArea(string value)
    {
        this._timeArea = value;
    }
}

例二:

.class public Program extends [mscorlib]System.Object
{
    .field private string _timeArea
    .method public static void Main()
    {
        .entrypoint
        .maxstack 1
        ldstr "Hello"
        call void [mscorlib]System.Console::WriteLine(string)
        call string [mscorlib]System.Console::ReadLine()
        ret
    }
    .method public void set_TimeArea(string 'value')//(string val)不用加单引号
    {
        .maxstack 1
        ldarg.0 //本操作码与value._timeArea = "aaa"无关
        ldarg.1 //本操作码对应value._timeArea = "aaa"中的value
        ldstr "aaa" //本操作码对应value._timeArea = "aaa"中的"aaa"
        stfld string GuoNameSpace.Program::_timeArea //本操作码对应value._timeArea = "aaa"中的._timeArea
        ret
    }
}

例二解释:

public class Program
{
    // Fields
    private string _timeArea;

    public static void Main()
    {
        // This item is obfuscated and can not be translated.
        Console.WriteLine("Hello");
    }

    public void set_TimeArea(string value)
    {
        // This item is obfuscated and can not be translated.
        value._timeArea = "aaa";
    }
}

例三:

.class public Program extends [mscorlib]System.Object
{
    .field private string _timeArea
    .method public static void Main()
    {
        .entrypoint
        .maxstack 1
        ldstr "Hello"
        call void [mscorlib]System.Console::WriteLine(string)
        call string [mscorlib]System.Console::ReadLine()
        ret
    }
    .method public void set_TimeArea(string 'value')//(string val)不用加单引号
    {
        .maxstack 1
        ldarg.0 //本操作码与"aaa"._timeArea = "bbb"无关
        ldarg.1 //本操作码与"aaa"._timeArea = "bbb"无关
        ldstr "aaa" //本操作码对应"aaa"._timeArea = "bbb"中的"aaa"
        ldstr "bbb" //本操作码对应"aaa"._timeArea = "bbb"中的"bbb"
        stfld string GuoNameSpace.Program::_timeArea //本操作码对应"aaa"._timeArea = "bbb"中的._timeArea
        ret
    }
}

例三解释:

public class Program
{
    // Fields
    private string _timeArea;

    public static void Main()
    {
        // This item is obfuscated and can not be translated.
        Console.WriteLine("Hello");
    }

    public void set_TimeArea(string value)
    {
        // This item is obfuscated and can not be translated.
        "aaa"._timeArea = "bbb";
    }
}

经过三个例子的对比发现,存储field时,stfld操作与堆栈顶部的两个值是密切相关的,执行stfld操作时堆栈最顶部的值就是field的值,位于堆栈次顶部的值表示field的所属对象。

CIL实现field加载

例一:

.class public Program extends [mscorlib]System.Object
{
    .field private string _timeArea
    .method public static void Main()
    {
        .entrypoint
        .maxstack 1
        ldstr "Hello"
        call void [mscorlib]System.Console::WriteLine(string)
        call string [mscorlib]System.Console::ReadLine()
        ret
    }
    .method public string get_TimeArea()
    {
        .maxstack 1
        .locals init(
            string timeArea
        )
        ldarg.0 //本操作码对应this._timeArea中的this
        ldfld string GuoNameSpace.Program::_timeArea //本操作码对应this._timeArea中的._timeArea
        stloc.0
        ldloc.0
        ret
    }
}

例一解释:

public class Program
{
    // Fields
    private string _timeArea;

    // Methods
    public string get_TimeArea()
    {
        return this._timeArea;
    }

    public static void Main()
    {
        // This item is obfuscated and can not be translated.
        Console.WriteLine("Hello");
    }
}


例二:

.class public Program extends [mscorlib]System.Object
{
    .field private string _timeArea
    .method public static void Main()
    {
        .entrypoint
        .maxstack 1
        ldstr "Hello"
        call void [mscorlib]System.Console::WriteLine(string)
        call string [mscorlib]System.Console::ReadLine()
        ret
    }
    .method public string get_TimeArea()
    {
        .maxstack 1
        .locals init(
            string timeArea
        )
        ldarg.0 //本操作码与"aaa"._timeArea无关
        ldstr "aaa" //本操作码对应"aaa"._timeArea中的"aaa"
        ldfld string GuoNameSpace.Program::_timeArea //本操作码对应"aaa"._timeArea中的._timeArea
        stloc.0
        ldloc.0
        ret
    }
}

例二解释:

public class Program
{
    // Fields
    private string _timeArea;

    // Methods
    public string get_TimeArea()
    {
        return "aaa"._timeArea;
    }

    public static void Main()
    {
        // This item is obfuscated and can not be translated.
        Console.WriteLine("Hello");
    }
}

例三:

.class public Program extends [mscorlib]System.Object
{
    .field private string _timeArea
    .method public static void Main()
    {
        .entrypoint
        .maxstack 1
        ldstr "Hello"
        call void [mscorlib]System.Console::WriteLine(string)
        call string [mscorlib]System.Console::ReadLine()
        ret
    }
    .method public string get_TimeArea()
    {
        .maxstack 1
        .locals init(
            string timeArea
        )
        ldarg.0 //本操作码与"bbb"._timeArea无关
        ldstr "aaa" //本操作码与"bbb"._timeArea无关
        ldstr "bbb" //本操作码对应"bbb"._timeArea中的"aaa"
        ldfld string GuoNameSpace.Program::_timeArea //本操作码对应"bbb"._timeArea中的._timeArea
        stloc.0
        ldloc.0
        ret
    }
}

例三解释:

public class Program
{
    // Fields
    private string _timeArea;

    // Methods
    public string get_TimeArea()
    {
        return "bbb"._timeArea;
    }

    public static void Main()
    {
        // This item is obfuscated and can not be translated.
        Console.WriteLine("Hello");
    }
}

经过三个例子的对比发现,加载field时,ldfld操作与堆栈最顶部的值是密切相关的,执行ldfld操作时堆栈最顶部的值表示field的所属对象。

翻旧账

不知道大家还记不记得静态方法中只能使用静态字段,为什么不能使用非静态字段呢?是时候解释一下了。
静态方法中ldarg.0表示方法的第一个参数,所以没办法使用ldarg.0来调用this.field;
非静态方法中ldarg.0表示this,所以可以使用ldarg.0来调用this.field。
就这么简单,不知道各位看明白了吗?欢迎各位留言提出宝贵意见。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

changuncle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值