前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MSIL学习------从HelloWorld开始

MSIL学习------从HelloWorld开始

作者头像
莫问今朝
发布2018-08-31 15:19:18
5330
发布2018-08-31 15:19:18
举报
文章被收录于专栏:博客园博客园

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3889z1y72b288

1.有没有必要学习IL

  前段时间突然想搞搞IL语言,于是在博客园中找到了包建强前辈关于IL的文章学习,并且在包前辈博客里看到了09年他与赵劼前辈关于是否有必要学习IL语言的争论,作为一个刚入此行业的新人,没有站在那个高度不敢去评论什么,并且我的引路教员在知道我学IL时就跟我说学习IL还不如学习汇编,IL语言就是一堆指令,谁背的多谁就越精通,我那个教员说的也不错,IL语言就是一堆指令,或许就是站的角度不同,我教员他不止局限于.NET,对C++和汇编都有一定研究,但是现在我还是只局限于.NET体系,学好.NET我感觉对于CIL和CLR一定得有一定的了解。所以我个人的观点是在.NET平台干活的人还是有必要学习学习IL的。现在IL我只是局限于刚学习阶段,所以想写下博客来记录我的学习记录

2.反编译解析HelloWorld

  学习IL,首先需要知道其各种指定的含义,所以需要先创建c#语言进行反编译来解析,在这里只需创建一个.CS类并使用命令进行编译与反编译即可,没必要启动宇宙第一IDE(VS)

代码语言:javascript
复制
using System;
namespace HelloWorld
{
    class HelloWorld
    {
        public static void Main(String[] args)
        {
            System.Console.WriteLine("HelloWorld");
        }
    }
}

  然后需要将.CS文件编译成.EXE文件,在这里需要什么VS的开发者工具(当然应该还有其它方式),

  使用SCS语句进行编译

代码语言:javascript
复制
csc HelloWorld.cs

  接下来使用ILDASM命令进行反编译为IL文件

代码语言:javascript
复制
ildasm HelloWorld.exe /output=HelloWorld.il

  然后就会生成一个.IL文件,这个文件进行HelloWorld.exe反编译后的代码

代码语言:javascript
复制
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                
  .ver 4:0:0:0
}
.assembly HelloWorld
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78  
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )      
  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module HelloWorld.exe
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       
.corflags 0x00000001    
.class private auto ansi beforefieldinit HelloWorld.HelloWorld
       extends [mscorlib]System.Object
{
  .method public hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "HelloWorld"
    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  ret
  } 
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } 
}

   下面来简单学习下这个IL代码

  •  可以看到IL中有需要 .assembly .module .class 这样规则的代码,它们是定义信息的伪指令,IL语言不像C#声明类似class时先写修饰符之类,而是首先定义声明的伪指令,先来看看每个伪指令的含义
  1. .assembly extern  [assemblyRefName] {}  [可选]  定义一个AssemblyRef(程序集引用)的元数据项,标记了这个程序使用的外部托管应用程序,类似using语句  mscorlib.dll:.NET程序集类库的主程序集。
  2. .assembly  [assemblyName] {}    定义一个程序集的元数据项,如果一个不定义此项,这个文件就不完全是一个应用程序,无法独立指定
  3. .module [moduleName] 定义一个模块元数据项,标识了当前的模块.
  4. .class  定义一个TypeDef(类声明)的元数据项
  5. .method  定义一个MethodDef(方法声明)的元数据项
  • 代码中像assembly和module只需要定义好就行,主要需要关注的还是class和method,当然还有field。下面再来介绍下修饰与class和method中的关键字

1.class

  1. private  访问修饰符,没什么好说的,IL支持6种访问修饰符,C#7.2版本才加入第六种(private protected)
  2. auto  [可选]  定义类的布局风格,auto是自动布局(默认值),只加载程序时可以使用它认为合适的方式进行布局   其它布局风格有sequential(加载程序时保留实例字段的顺序)和explicit(显示指定类型布局)
  3. ansi  [可选]  定义类中字符串与其它非托管代码进行操作时的转换模式,  ansi指定了会与”标准“C风格的字节字符串进行转换(默认值),其它有unicode(与UTF-16字符进行转换)和autochar(有底层平台定义的默认字符串转换)
  4. beforefieldinit  [可选]  指静态成员在第一次访问之前被初始化
  5. extends   继承    也没什么好说的

     另外可以看到C#中写的命名空间在IL中直接变成了一个完整类名。这是IL2.0时引入的,

2.method

  1. public   访问修饰符
  2. hidebysig  用于隐藏父类的同名方法,类似于C#的new关键字
  3. specialname  提示编译器和工具这个函数时特殊的,  只存在与构造函数(.ctor)和静态构造函数(.cctor)中
  4. rtspecialname  告诉运行时这个函数时特殊的  只存在与构造函数(.ctor)和静态构造函数(.cctor)中
  5. static/instance  static 声明这个函数时静态函数     instance:声明这个函数时实例函数
  6. cil managed  声明这个函数时CIL代码

  了解了IL代码整体结构后接下来来看下方法,方法体中通常包含三项:指令,标注了指令的标号和伪指令(在方法体外只有伪指令),在方法中像.entrypoint.maxstack这类是伪指令,nop,ldstr这属于指定,而IL_0000属于指令标号,指令标号作用是跳转时使用,所以自己写代码时没必要每行都加,只有在需要时加入即可,另外标号不会对伪指令进行标注

  在上面C#代码中只定义了一个Main方法,但是在IL文件中却存在两个方法,其中一个方法就是定义的Main方法,而另一个则是C#编辑器加上的默认构造函数(.ctor),从这里可以看出C#的一个知识点(未添加构造函数C#会自动添加一个默认构造函数)

       构造函数在此不介绍,只说一下Main方法中的内容,

       .entrypoint和.maxstack是两个伪指令,它们的作用分别是.

      .entrypoint:将定义此伪指令的方法标识为应用程序入口方法,也就是说在IL中程序入口并不是方法名称为Main的,

      .maxstack:栈中存在的最大数量数据,比如Main方法maxstack=8则说明stack中最多容纳8个数据。(IL栈元素不是字节或字,而是槽,当谈论IL栈深度时,指的是放在栈中的项,而不考虑项的大小)

    nop  指令代表如果修补操作码,则填充空间,但时是并不执行任何有意义的操作

         ldstr  代表加载一个字符串到栈顶

    call   方法调用指令,还有另一个方法调用指令为callvirl,在IL中调用方法使用是“::” 而不是C#中的“.”,并且调用前要先声明其返回值类型和参数并不是C#的那种实参变量而是参数的类型,因为IL是一种严格基于栈的语言,方法时会按照参数列表去栈顶进行获取数据,调用完成后如果有返回值也会将返回值放入栈顶

    ret  从当前方法返回,并将返回值(如果存在)放入调用方的计算栈中

3.编写一个IL语言的HelloWorld

  通过上面的解析可以看出手写一个简单的IL语言的HelloWorld其实挺简单,只需要依葫芦画瓢就可以

代码语言:javascript
复制
.assembly extern mscorlib{ auto}
.assembly HelloWorld_IL{}
.module HelloWorld.HelloWorld_IL.exe 
.class private auto ansi HelloWorld.Program extends [mscorlib]System.Object
{
    .method public hidebysig rtspecialname specialname instance void .ctor()cil managed
    {
        ldarg.0
        call instance void [mscorlib]System.Object::.ctor()
        ret 
    }
    .method public hidebysig static void MyMain()cil managed
    {
        .entrypoint
        .maxstack 1
        ldstr "HelloWorld"
        call void [mscorlib]System.Console::WriteLine(string)
        ret 
    }
}

  在上面代码中程序集引用中使用的是auto,这是IL2.0版本加入,会自动搜索指定名称程序集

  然后在开发者工具使用命令进行编辑

代码语言:javascript
复制
ilasm HelloWorld_IL.il /output=HelloWorld_IL.exe

  然后指定就可以看出HelloWorld输出

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-07-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3889z1y72b288
  • 1.有没有必要学习IL
  • 2.反编译解析HelloWorld
  • 3.编写一个IL语言的HelloWorld
相关产品与服务
云开发 CLI 工具
云开发 CLI 工具(Cloudbase CLI Devtools,CCLID)是云开发官方指定的 CLI 工具,可以帮助开发者快速构建 Serverless 应用。CLI 工具提供能力包括文件储存的管理、云函数的部署、模板项目的创建、HTTP Service、静态网站托管等,您可以专注于编码,无需在平台中切换各类配置。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档