.Net8罕见的技术:MSIL的机器码简析

2023-07-30,,

前言

一般的只有最终的汇编代码才有机器码表示,然一个偶然的机会发现,MSIL(Microsoft intermediate language)作为一个中间语言表示,居然也有机器码,其实这也难怪,计算机里面万物都是二进制,本篇来看下,以下以.Net8 PreView Source Code分析为主。原文:在此处

概括

1.C# And IL

先上C#代码:

static void Main()
{
Program pm=new Program();
GC.Collect();
Console.WriteLine("CeShi JITDUMP");
Console.ReadLine();
}

非常简单的一段代码,把这段代码编译后的DLL导入到微软官方的ILDASM工具里面去,可以看到如下代码:

.method private hidebysig static void  Main() cil managed
{
.entrypoint
// 代码大小 28 (0x1c)
.maxstack 8
IL_0000: newobj instance void Program::.ctor()
IL_0005: pop
IL_0006: call void [System.Runtime]System.GC::Collect()
IL_000b: ldstr "CeShi JITDUMP"
IL_0010: call void [System.Console]System.Console::WriteLine(string)
IL_0015: call string [System.Console]System.Console::ReadLine()
IL_001a: pop
IL_001b: ret
} // end of method Program::Main

这里注意下标号IL_0000的那段代码:

IL_0000:  newobj     instance void Program::.ctor()

以此为例子作为观察。

2.JIT Import IL

来看下JIT把这段IL代码导入后的一个情况

IL to import:
IL_0000 73 04 00 00 06 newobj 0x6000004
IL_0005 26 pop
IL_0006 28 0e 00 00 0a call 0xA00000E
IL_000b 72 01 00 00 70 ldstr 0x70000001
IL_0010 28 0f 00 00 0a call 0xA00000F
IL_0015 28 10 00 00 0a call 0xA000010
IL_001a 26 pop
IL_001b 2a ret

注意到JIT导入这段IL代码之后,多了机器码,多了十六进制的表示。以IL_0000段代码为例

导入之前:

 IL_0000:  newobj     instance void Program::.ctor()

这里newobj之前没有机器码,newobj之后是调用了函数instance void Program::.ctor()。

导入之后:

IL_0000  73 04 00 00 06    newobj       0x6000004

这里很明显看到变化,newobj之前有一连串的机器码:73 04 00 00 06。newobj之后,则有十六进制0x6000004取代了上面的函数调用:instance void Program::.ctor()。

3.分析

那么IL里面的这些机器码和十六进制数值是干什么用的呢?

首先看下机器码:73 04 00 00 06。一个个的看。

首先的0x73,它表示的是:newobj的机器码。它的原型是:

OPDEF(CEE_NEWOBJ, "newobj",VarPop,PushRef,InlineMethod,   IObjModel, 1,0xFF,0x73,CALL)

后面的04 00 00 06这四个字节的机器码可以看做一个整体,小端取值那么它的值是:6000004。

那么这个6000004到底表示什么东西呢?通过ILDASM的快捷键Ctrl+M打开元数据信息,里面可以看到6000004表示的就是.ctor函数的元数据描述,它的原型如下:

Method #2 (06000004)
-------------------------------------------------------
MethodName: .ctor (06000004)
Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName] [RTSpecialName] [.ctor] (00001886)
RVA : 0x00002084
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.

那么这段代码

IL_0000  73 04 00 00 06    newobj       0x6000004

的整体意思就很清楚了,73 04 00 00 06里面的73是表示newobj,后面的04 00 00 06表示调用.ctor非静态构造函数。它实际上跟ILDASM里面显示的IL代码是同一个意思,但是因为在内存里面操作,所以它只能是十六进制或者二进制,JIT导入的时候只不过把字母的含义替换成了具体数字的含义。其它的IL代码依次类推。

结尾

作者:江湖评谈

文章首发在公众号(jianghupt)上,欢迎关注

.Net8罕见技术:MSIL的机器码简析的相关教程结束。

《.Net8罕见的技术:MSIL的机器码简析.doc》

下载本文的Word格式文档,以方便收藏与打印。