.Net CLR运行时是如何编译函数的

首先了解几个概念和内存结构

一:
1.函数描述符MethodDesc,包含了函数是否被编译标志,函数当前在函数描述符块的索引,以及函数在函数表的索引,以及Token
2.函数描述符块MethodDescChunk,主要是包含了当前函数描述符的个数
3.函数入口点FixupPreCode 包含了函数描述符的索引,FixupPreCode的索引

二:
1.内存结构排列
FixupPreCode->MethodDescChunk->MethodDesc
假如说有一块连续内存:1-2-3-4-5-6实际上可以把上面三个结构体看做1,2,3连续内存存储模式。
注意看下图(不必理解为什么意思,只需要知道他们的内存排列结构就可以了)
在这里插入图片描述
红色和黄色框出来的就是fixupprecdoe也就是地址为0x00007fff6D79A7E0以及地址0x00007fff6D79A848,仔细看这两个地址的值都是00007fff6d7a0828也就是fixupPreCode的地址值。跳转到这个地址,它的值为00005e5ed11113e8。
蓝色框出来的就是MethodDescChunk ,紫色的为MethodDesc。

CLR在运行的时候,首先会在方法描述符块地址-1的地方放置FixUpPrecode的地址值,也就是通过&MethodDescChunk-1就可以访问当前所有类的函数入口点。

在设置函数描述符的时候,CLR会把非虚函数的函数入口点放在MethodDesc的结尾,也就是上面黄色框的地方,地址为0x00007fff6D79A848

通过上面内存结构,其实我们可以看到只要知道函数入口点,函数描述符,以及函数描述符块其中一个的内存地址,就可以推导出其它几个结构体地址以及存储的值。

三:
1.当我们的函数被编译之后,函数描述符结尾的函数入口点就会改为被编译后的地址。也就是地址0x00007fff6D79A848会被改动。而在函数编译之前的地址,实质上就是PrecodeFixupThunk,改动之后,就是机器码的地址。

2.在改动函数入口点之后,他会修改函数描述符,也就是MethodDesc结构体里面的地址为&MethodDesc+0x08的值。它会标记当前函数已经被编译,以及编译后的地址是多少。

3.在以上两步完成之后,就会修改函数入口点的值,注意第一步是修改函数入口点的跳转值。也就是FixupPreCode的本身值。

关于以上我们可以通过代码来验证。

四:
1.假设我们有以下代码:

using System;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            Test.testmethod(1);
        }
    }
    public static class Test
    {
        public static void testmethod(int i)
        {

        }
    }

}

反汇编可以看到它调用Test.testmethod(1);函数之后,它会跳转到地址0x07FFF67040640在这里插入图片描述
查看下此地址的值
在这里插入图片描述
我们可以看到fixuppreocde值后面接着MethodDesc的地址。通过其地址就可以找到TestMethod1函数的内存结构
在这里插入图片描述
注意看,有两个fixupprecode地址,也就是两个紫色线条指向的地方。为啥,看上面内存结构排序的那张图,跟这张图一模一样。都是头尾为fixupprecode地址,后面跟着methoddeschunk,然后再跟着methoddesc。
我们F5把断点直接运行testmethod函数。
看函数被编译后的下面两张图

fixupprecode图:
在这里插入图片描述
methoddesc图:
在这里插入图片描述
我们看到fixupprecode的值变了,从5e5f5eb29be8变成了5f000035cbe9.但是同时我们也看到methoddesc没有改变,那么问题来了,我们是如何知道mehtoddesc是被编译过了,它那个编译标记是如何被设置的呢,这个问题先放一放。
回到上面
我们看到,当一个函数被编译前后,它的入口点地址是不变的也就是恒值,而变的是入口点的值。编译之前入口点值被设置成调用PrecodeFixupThunk函数的值,而编译之后被设置成编译后机器码的值。
以上大致就是CLR编译函数的过程了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值