当前位置: 首页 > 编程日记 > 正文

Cosmos的基石:IL2CPU编译器--.net/C#开源操作系统学习系列三

本文的代码包以cosmos-12304.zip为例(从这个包开始,COSMOS的内核算是有了个基本的雏形,就像是一颗大树在出芽前会先长出庞大的根系,现在就要破土长出第一颗芽了)

IL2CPU之于COSMOS就相当与GCC之于LINUX,查看COSMOS的源代码,可以发现没有一行汇编代码,就连BOOTLOADER也是使用C#语言来完成的,在COSMOS中很对与硬件相对应的类,如屏幕、键盘等,然后在编译的时候再由IL2CPU识别出这些特定的类并转换成机器指令代码代码。

由于是纯C#的开发环境,因此IL2CPU责任重大,需要实现C#语言的各种特性,包括对象的初始化、多态、事件、委托等等,当然到cosmos-12304为止,这些特性还没有全部实现(后面的应该会一步一步的都实现,不过还没有看过后面的源代码,只是猜测而已)。除此之外,IL2CPU还负责处理对.net的运行库(这个运行库并不是.net framework,这个库是COSMOS自己实现的与.net framework类似但要小很多很多的一个库,以后再讲这一部分)

cosmos-12304这个版本的代码和现在最新的代码在文件结构上有很大的差别,之所以文章从这个代码包开始,是因为小弟从第一个源代码包开始,一点一点的挪到这里,个人感觉从这里开始终于可以大致的抓住了COSMOS的开发思路,目前的COSMOS应该可以分成两部,一部分是IL2CPU,一部分是操作系统内核。整个COSMOS项目是从IL2CPU开始的(从早期的代码可以看出,全都是在实现的编译器的任务),先是让IL2CPU能把简单的C#程序编译成本地程序之后,就开始实现操作系统内核,随着项目的深入,一遍扩展内核的功能,一遍完善IL2CPU编译器,小弟估计到后期IL2CPU将会支持全部C#语言乃至整个MSIL语言的所有特性。

好了,废话到这该来点实质性的东西了,cosmos-12304中先修改启动项目为这个

该项目调用了一段脚本用来编译并启动COSMOS的内核,脚本内容如下:

 

..\..\..\source\il2cpu\bin\debug\il2cpu.exe 
-metal 
-in:..\..\..\source\Cosmos\Cosmos.Shell.Console\bin\debug\Cosmos.Shell.Console.exe 
-plug:..\..\..\source\Cosmos\Cosmos.Kernel.Plugs\bin\debug\Cosmos.Kernel.Plugs.dll 
-out:Files\output.obj -platform:nativex86 -asm:output.asm

脚本位于cosmos-12304\Build\Cosmos\ISO目录下,文件名为Build.bat(其实就是一段批处理程序.........)。设置完后F5启动,整个项目就开始运行了

成功运行的截图如下:

 

运行方式为把内核编译生成ISO文件,然后使用QEMU虚拟机加载(关于运行如何启动可以参考小弟的上一篇文章,使用的工具不太一样,但是流程是相同的)

好了,到这里整个项目算是运行完成了(对!就只有两行输出,雏形......雏形,大家见谅,就相当于可以输出一个“hello world”了)

接下来看看IL2CPU是如何把C#代码转换成可以独立运行的操作系统内核的,痛苦的历程开始了(小弟编译原理和操作系统原理没学好,分析这里的代码是在是太痛苦了)

Build.bat文件中的脚本可以看出,启动的时候运行的是IL2CPU项目,直接来到该项目下,点开,查看,是一个CONSOLE类型的项目,直接来到Main函数里面,分析源代码可以发现,IL2CPU项目根据-in输入参数来确定要编译的程序集--此处输入的项目为Cosmos.Shell.Console项目--Main函数中找到如下代码:

 

using (FileStream fs = new FileStream(AsmFile, FileMode.Create)) 
{
    
using (StreamWriter br = new StreamWriter(fs)) 
        {
        e.Execute(InputFile, TargetPlatform, br, MetalMode, DebugMode, BCLDir, Plugs);
    }
}

主要关注这一句:

e.Execute(InputFile, TargetPlatform, br, MetalMode, DebugMode, BCLDir, Plugs);

此处e为一个ENGINE类型的对象在上边有实例化的代码,跳到Execute方法的定义处,函数内容如下........额,太长了就不列出来,有兴趣的朋友可以自己查看下源代码J

可以看到IL2CPU先获取了Cosmos.Shell.Console程序集的信息,然后存到一个本地变量中,

mCrawledAssembly = AssemblyFactory.GetAssembly(aAssembly);

然后就可以从这个变量中获取程序集都另外引用了哪些程序集,再把引用到的程序集都添加到mCrawledAssembly变量内,在mCrawledAssembly内部使用一个List<AssemblyDefinition>类型的变量来存储这些程序集,留到后面生成汇编代码的时候使用(注:此处使用了MONO项目中的一些类,如AssemblyFactoryAssemblyDefinition,求一份MONO的类库文档,英文的也行),除此之外还加载了Plugs(插件?),目前看来,Plugs就相当于COSMOS库,COSMOS中对外部硬件的操作都通过Plugs(库)来实现,目前只实现了CONSOLE这个类,也就是说,COSMOS内核中使用的CONSOLE类不是.net framework中的CONSOLE类,而是由CONSOLE内核重新实现了的,在CONSOLE内部调用特定的对象(以后分析)来实现输出功能,当然CONSOLE实现的方法和属性都与.net framework中的一样,这样在编程的时候只需直接使用.net framework来完成操作即可,等到了编译阶段IL2CPU会自动把相应的代码转换成COSMOS的内部实现从而脱离对.net framework库的依赖。

个人猜测以后Plugs会扩展成一个像.net framework一样的类库,不过.net framework的类库这么庞大……恐怕……………

完成以上这些操作后,IL2CPU还会加入一些初始化运行时的函数:

ExpandedBlockStart.gif代码
mMethods.Add(RuntimeEngineRefs.InitializeApplicationRef, new QueuedMethodInformation() {
                            Processed 
= false,
                            Index 
= mMethods.Count
                        });
                        mMethods.Add(RuntimeEngineRefs.FinalizeApplicationRef, 
new QueuedMethodInformation() {
                            Processed 
= false,
                            Index 
= mMethods.Count
                        });

和虚表(用来实现多态)的实现(对多态的底层实现不是很了解,这里只知其然并不知其所以然,惭愧):
ExpandedBlockStart.gif代码
if (!aInMetalMode) {
                            mMethods.Add(VTablesImplRefs.LoadTypeTableRef, 
new QueuedMethodInformation() {
                                Processed 
= false,
                                Index 
= mMethods.Count
                            });
                            mMethods.Add(VTablesImplRefs.SetMethodInfoRef, 
new QueuedMethodInformation() {
                                Processed 
= false,
                                Index 
= mMethods.Count
                            });
                            mMethods.Add(VTablesImplRefs.SetTypeInfoRef, 
new QueuedMethodInformation() {
                                Processed 
= false,
                                Index 
= mMethods.Count
                            });
                            mMethods.Add(VTablesImplRefs.GetMethodAddressForTypeRef, 
new QueuedMethodInformation() {
                                Processed 
= false,
                                Index 
= mMethods.Count
                            });
                        }


完了之后会传入内核程序的入口点,这就是为什么很多语言的程序都是以Main函数作为程序入口点的原因,因为编译器内部定义的就是把程序跳到Main函数开始执行,如果想让别的函数作为开始函数,则在编译器中就得做相应的修改,有时候这部分内容也交由连接器来处理(有关连接器和编译器的作用在此推荐本书《程序员的自我修养连接、装载与库》)

mMethods.Add(mCrawledAssembly.EntryPoint, new QueuedMethodInformation() {
                            Processed 
= false,
                            Index 
= mMethods.Count
                        });

之后就会调用ProcessAllMethods()方法把以上传入的所有程序集里面的方法转换成汇编代码,然后还会有些清理作用的函数,最后是调用ProcessAllStaticFields()处理一些全局的静态变量

有兴趣的朋友可以跟进代码里面研究一下转换的过程,小弟实在是顶不住了,看得眼花花、头晕晕,大家知道是这么一个流程就好,以后的编译过程基本上就是走的这么一个流程,下面是小弟总结出来的IL2CPU的编译流程图,欢迎大家拍砖:

从上图中没有看到传统编译器中还需要进行的语法、词法、文法分析这几步,嘿嘿,其实这些步骤在加载之前就都已经完成了,这是因为IL2CPU中加载的需要编译的文件都是程序集文件,而.net中,可以通过反射来查看程序集中的所有定义的函数、变量之类的内容,相当于.net已经帮我们做完了语法、词法、文法分析,并把分析的结果分门别类的存放在程序集里了,我们只需要通过反射功能来查看程序集中已经分类好的信息即可。其实,上图中除了分析和汇编的操作,其他的都是把各个需要用到的程序集中的函数、变量这些东西取出来,再补充上一些额外的初始化操作。而分析和汇编的任务就是把从各个程序集中取出函数、变量翻译成本地CPU代码。在IL2CPU内部,是通过逐条翻译MSIL指令来完成的。

可以点开看一下Indy.IL2CPU.IL.X86项目(最新的代码包中好像已经被更名为Cosmos.Complier.IL2CPU.IL.X86

里面对每一调MSIL指令都写了一个与其对应的类,每一个类就是专门负责把其自己翻译成X86的指令。

上面的这些函数小弟跟进去看了一下,在此以目前的水平就展开分析,展开了也说不清,但里面的东西确实都是精华,虽然复杂了点,但是对于学习面向对象程序的结构和编译器实现的朋友来说是一个很好的例子,在此推荐

最后,IL2CPU再使用第三方工具,把汇编出来的汇编指令文件转换成本地CPU识别的二进制文件,代码如下:

ExpandedBlockStart.gif代码
ProcessStartInfo xFasmStartInfo = new ProcessStartInfo();
                    xFasmStartInfo.FileName 
= FasmFileName;
                    xFasmStartInfo.Arguments 
= String.Format("\"{0}\" \"{1}\"", AsmFile, OutputFile);
                    xFasmStartInfo.UseShellExecute 
= false;
                    xFasmStartInfo.RedirectStandardError 
= true;
                    xFasmStartInfo.RedirectStandardOutput 
= true;
                    Console.WriteLine(
"fasm = '{0}'", FasmFileName);
                    Process xFasm 
= Process.Start(xFasmStartInfo);
                    xFasm.Start();
                    
if (!xFasm.WaitForExit(60 * 1000|| xFasm.ExitCode != 0) {
                        Console.WriteLine(
"Error while running FASM!");
                        Console.Write(xFasm.StandardOutput.ReadToEnd());
                        Console.Write(xFasm.StandardError.ReadToEnd());
                        
return 3;
                    }

最后,在通过脚本,讲二进制文件转换成ISO文件供虚拟机加载运行:

@REM ----------- Build ISO

del cosmos.iso

attrib files\boot\grub\stage2_eltorito -r

..\..\..\Tools\mkisofs\mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o Cosmos.iso files

pause

@REM ----------- Start QEMU

cd ..\..\..\tools\qemu\

qemu.exe -L . -cdrom ..\..\build\Cosmos\ISO\Cosmos.iso -boot d

pause

最后附上一个comos-12304.zipIL2CPU相关项目的说明(当然也是个人学习的总结,可能有错,仅当参考,欢迎拍砖)

IL2CPUIL2CPU的启动项目

IL2CPU.Tests:用来测试对MSIL的指令的翻译是否正确的测试项目

IL2CPUGUI:暂时无用

Indy.IL2CPUIL2CPU的编译引擎主要的活动都发生在这里面同时封装了用来实现MSIL特性的类,如垃圾收集器、多态等

Indy.IL2CPU.Assembler实现汇编器的一些基类和一些通用的指令操作

Indy.IL2CPU.Assembler.X86X86汇编器,封装X86指令的实现

Indy.IL2CPU.Assembler.X86.NativeX86汇编器的一些扩展,应该是用来封装一些平台特有的指令

Indy.IL2CPU.Assembler.X86.Win32X86汇编器的扩展用来翻译支持WIN32环境下的汇编程序

Indy.IL2CPU.IL:封装MSIL指令的一些基类和一些通用的操作

Indy.IL2CPU.IL.X86Indy.IL2CPU.Assembler.X86项目配合,把MSIL指令翻译成X86指令

Indy.IL2CPU.IL.X86.NativeIndy.IL2CPU.Assembler.X86.Native项目配合,把MSIL指令翻译成一些平台支持的特有一些特性的指令

Indy.IL2CPU.IL.X86.Win32与上面两个类似翻译成Win32环境下的汇编指令

Indy.IL2CPU.Plugs:封装一些用来在编译的时候处理Plugs的类和操作

最新的代码包中,以上项目的名字已经被该动,不过也只是前缀进行了改变,面的部分基本上都一样。同时个人觉得IL2CPU也还是很不错的编译器,学习编译原理的朋友门,小弟在次推荐一下可以研究一下IL2CPU的源代码,也可以写些文章出来帮小弟解惑一下,呵呵J

好了,先写到这里吧,水平有限,写得不是很好,留下的一些问题特别是关于Plugs的内容小弟也会在以后对源码的学习中慢慢解开

如果觉得本文有点帮助的朋友楼主是很乐意接收鼓励的J,可以到楼主的淘宝充值店光顾下(欢迎收藏小店……广告….广告,大家懂的~~~~或者点击下博客里面的广告,呵呵

有大虾路过的话楼主也愿意接受鸡蛋和板砖。

相关文章:

【面试 多线程】【第九篇】多线程的问题

1.多线程有什么用 发挥多核CPU优势&#xff0c;防止阻塞&#xff0c;更快的处理数据 2.多线程的实现方式有哪几种&#xff0c;分别的特点优势是什么样的 1》继承Thread类&#xff0c;重写run方法&#xff0c;start启动多线程 2》实现Runnable接口&#xff0c;重写run方法&…

那个大战AlphaGo的柯洁,将免试入读清华大学工商管理专业

日前&#xff0c;柯洁将免试入读清华大学的消息经媒体曝光了出来。《2019 年优秀运动员免试入学推荐名单》3 月 10 日开始公示&#xff0c;围棋世界冠军柯洁的名字出现在名单上&#xff0c;其中表明他将就读清华大学工商管理类专业。据了解&#xff0c;柯洁预计今年下半年入学清…

【Qt】设置背景

1、使用样式表qss设置背景 QDialog 设置背景图片: dlg->setStyleSheet("QDialog{border-image: url(://test.png);}"); 设置背景颜色: dlg->setStyleSheet("QDialog{background-color: red;}"); QWidget 设置背景图片: wgt->setStyleSheet…

基于Hadoop的MapReduce框架研究报告

http://www.doc88.com/p-19830708273.html

【Qt】设置窗口透明度

1、使用setWindowOpacity设置透明度 setWindowOpacity(0.5); 设置完成会使窗体、标题栏、子控件都透明 2、使用样式表qss设置窗体透明 dlg->setStyleSheet("QDialog{background-color: rgba(255, 0, 0, 0.5);}");wgt->setStyleSheet("QWidget{backgrou…

7行Python代码,搭建可以识花的机器学习App|视频教程

你想学Python&#xff0c;却不知如何着手&#xff0c;那你需要一种更加有趣的学习方式。Siraj Raval是一位人工智能领域的编程高手&#xff0c;毕业于哥伦比亚大学&#xff0c;曾任职于 Twilio 和 Meetup&#xff0c;他通过制作教程类短视频的方式在Youtube上积累了大量的粉丝&…

java中缀表达式转后缀表达式(逆波兰算法)

四则运算是栈的重要应用之一 中缀表达式转后缀表达式&#xff08;逆波兰算法&#xff09;过程 从左到右遍历中缀表达式数字直接输出为后缀表达式一部分如果是符号&#xff0c;则判断与栈顶元素的优先级高于栈顶元素优先级直接入栈低于或等于栈顶优先级栈顶元素出栈并输出为后缀…

Wpf消息循环之消息传递

几天遇见一个问题需要检查某个wpf程序是否已经运行&#xff0c;如果没有运行则启动传递参数&#xff0c;如果已运行则需要直接传递消息。在没有运行 情况下传递参数很简单&#xff0c;我们只需要Process cmd窗口启动并传递参数&#xff0c;在程序中处理。但是如果程序已经启动有…

【Qt】使用sqlite3数据库时,主键自增和获取自增后的主键的

创建数据表格&#xff0c;设置主键自增 创建数据库时&#xff0c;启用主键自增加特性 Create table testTable (id INTEGER PRIMARY KEY AUTOINCREMENT,。。。。 注意事项&#xff1a;设置主键自增时&#xff08;AUTOINCREMENT&#xff09;&#xff0c;主键类型必须是INTEGER&…

拿下斯坦福和剑桥双offer,00后的算法学习之路

董文馨&#xff0c;00后&#xff0c;精通英语&#xff0c;西班牙语。斯坦福大学计算机系和剑桥大学双Offer&#xff0c;秋季将进入斯坦福大学学习。10岁开始在国外上学&#xff1b;12岁学Scratch&#xff1b;13岁学HTML & CSS&#xff1b;14岁开始学Python & Java&…

Mybatis【配置文件】就是这么简单

配置文件和映射文件还有挺多的属性我还没有讲的&#xff0c;现在就把它们一一补全 映射文件 在mapper.xml文件中配置很多的sql语句&#xff0c;执行每个sql语句时&#xff0c;封装为MappedStatement对象&#xff0c;mapper.xml以statement为单位管理sql语句 Statement的实际位置…

cto denalil

Denali使用准虚拟化技术来提高x86电脑上虚拟机的性能。Denali的虚拟机为因特网服务专门支持了最小化的操作系统。 系统可以运行上千虚拟机。Xen与Denali不同&#xff0c;因为它试图运行适当数量的完整操作系统&#xff0c;而非大量轻量级操作系统。转载于:https://blog.51cto.c…

Redis学习笔记 - 数据类型与API(1)Key

Redis学习笔记 - 数据类型与API&#xff08;1&#xff09;Key Key相关命令 1. 常用命令 命令含义时间复杂度keys查找所有符合给定模式 pattern 的 keyO(N)&#xff0c; N 为数据库中 key 的数量dbsize计算key的总数O(1)exists检查key是否存在O(1)del删除指定的key-valueO(1)exp…

【Qt】enum和QString的相互

使用Q_ENUM注册enum Q_ENUM使用元对象系统meta-object来注册,因此在enum所在的类中必须包含宏Q_OBJECT或者Q_GADGET。 例子如下 class MyClass : public QObject{Q_OBJECTpublic:MyClass(QObject *parent = 0);~MyClass();enum Priority { High, Low, VeryHigh, VeryLow };Q_…

Gmail全球大规模宕机

整理 | 非主流出品 | AI科技大本营&#xff08;ID: rgznai100&#xff09;今天&#xff08;3 月 13 日&#xff09;&#xff0c;Google 的多项服务在全球范围内出现了不同程度的宕机&#xff0c;包括 Gmail、Google Drive、 Hangouts、谷歌地图等。受影响最大的是拥有超 10 亿用…

搭建域控服务器

作业环境 服务器端(VirtualBox VM) 操作系统&#xff1a;Windows Server 2003 Enterprise Edition SP2 IPAddress&#xff1a;192.168.1.1/255.255.255.0 Gateway&#xff1a;null 客户端(VirtualBox VM) 操作系统&#xff1a;Windows XP SP3 IPAddress&#xff1a;192.168.1.2…

【Git】ubuntu安装git

sudo apt-get install git 图形界面的&#xff1a;sudo apt-get install git-gui 查看ssh服务是否启动 sudo ps -e | grep ssh 如果没有启动执行如下命令&#xff1b; sudo service ssh start 如果没有ssh&#xff0c;使用如下命令安装 sudo apt-get install ssh

Composer 篇

学习网站Composer 中文网 资源包 Packagist Packagist / Composer 中国全量镜像如何安装 Composer下载 Composer安装前请务必确保已经正确安装了PHP。打开命令行窗口并执行php -v查看是否正确输出版本号。打开命令行并依次执行下列命令安装最新版本的 Composer&#xff1a;php …

西工大开源拥挤人群数据集生成工具,大幅提升算法精度 | CVPR 2019

作者 | 周强&#xff08;CV君&#xff09;转载自 我爱计算机视觉&#xff08;公众号id&#xff1a;aicvml&#xff09;近年来&#xff0c;因为拥挤人群计数在视频监控、公共安全方面的应用广泛&#xff0c;引起了不少学者的关注。简单说来这个任务就是给定图像&#xff0c;返回…

getElementById 不能取得visible=false 的控件解决方法

想要绑定textbox的回车事件到一个按钮上&#xff0c;但不想显示这个按钮&#xff0c;如果你把这个button的visible设置为false,那么你使用 getElementById是获取不到的&#xff0c;或者说取到的为空。这是因为Visiblefalse&#xff0c;在编译后&#xff0c;该控件在页面上不显示…

【Git】在本地创建git库管理自己的代码

1、创建本地库 git init . 新建库 git config --global user.email “hello163.com” git config --global user.name “laoer” git config --global core.editor vim //将默认编辑器由nano更改为vim 2、提交 2.1 git add . 将当前目录下所有文件添加到提交缓冲区 2.2 git …

“智慧血联网平台”亮相军民融合技术装备博览会

该平台可实现血液全程跟踪溯源&#xff0c;为大众提供安全、透明、便捷的用血服务。 一个打造智慧化血液管理新模式的血联网平台最近亮相第三届中国军民融合技术装备博览会。该平台可实现血液全程跟踪溯源&#xff0c;为大众提供安全、透明、便捷的用血服务。 此次博览会以“聚…

AI专利之争:小米超华为,国家电网才是大Boss?

作者 | 一一编辑 | 琥珀出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;以往相关机构发布 AI 专利数量排行榜时&#xff0c;如果表明“中国在 AI 专利申请数量上已经超过美国&#xff0c;中国在 AI 技术实力上已在国际上遥遥领先”&#xff0c;这类榜单会招致对中国科…

SLF4J 的几种实际应用模式--之二:SLF4J+Logback

前面讲的 SLF4J 的用法之一是 SLF4JLog4J&#xff0c;而这里要推出的组合是 SLF4JLogBack。不用 Log4J&#xff1f;难道还有比 Log4J 更好的日志实现吗&#xff1f;是的&#xff0c;答案就是 LogBack。假如你知道 LogBack 和 Log4J 是同出一位大师之手&#xff0c;你就不会觉得…

10行Python,搭建一个游戏AI | 视频教程

昨天为大家推荐了三个Python视频&#xff0c;包含&#xff1a;《利用Python&#xff0c;用4分钟时间搭建一个情感分析系统》、《7行Python代码&#xff0c;搭建一个可以识花的机器学习APP》、《10行Python&#xff0c;搭建一个可以自动作曲的神经网络》&#xff0c;今天营长再为…

ABAP git客户端

Jerry习惯把自己写的小程序放到自己的github上&#xff1a;https://github.com/i042416 对于写的ABAP程序&#xff0c;需要先把SAPGUI里的代码手动拷贝到本地&#xff0c;然后用git客户端push到github上。 但是其实可以直接在SAPGUI里通过一个ABAP实现的git客户端将代码push到g…

【Git】git 与远程库交互

一、远程操作 1、克隆 git clone <url> 2、提交 git add &#xff1a;添加 git commit -m “修改信息” &#xff1a;提交到本地 git branch -a &#xff1a;查看所有分支&#xff0c;红色的是远程分支 git fetch &#xff1a;获取远程分支 git diff HEAD FETCH_HEAD…

[轉]在jQuery1.5中使用deferred对象 - 拿着放大镜看Promise

http://www.cnblogs.com/sanshi/archive/2011/03/11/1981789.html 不錯的JS方面的文章 三生石上

拼多多成立技术顾问委员会,陆奇将领导相关工作

整理 | 琥珀出品 | AI科技大本营&#xff08;公众号id&#xff1a;rgznai100&#xff09;美国东部时间 3 月 13 日上午&#xff0c;拼多多&#xff08;NASDAQ&#xff1a;PDD&#xff09;公布了截止 2018 年 12 月 31 日的第四季度和全年年的未经审计财务业绩。拼多多创始人、C…

【linux】Valgrind工具集详解(一):简介

一、Valgrind概述 Valgrind是用于构建动态分析工具的仪器框架。它附带了一组工具&#xff0c;每个工具都执行某种调试&#xff0c;分析或类似任务&#xff0c;可帮助您改进程序。Valgrind的架构采用模块化设计&#xff0c;因此可以轻松创建新工具&#xff0c;而不会干扰现有结…