前言
创作动机
最近一段时间在和MMIX打交道,但是发现两件事情——第一是国内有关资料介绍很少,找得到的质量也不高(第一是排版丑,然后是对新手很不友好)因此我现在希望创作一个真正给新手看的,一眼能够看得懂的MMIX语言指导。
什么是MMIX?
MMIX 是由高德纳(Donald Ervin Knuth)创造的RISC指令集,是一种汇编语言(和平常你打开Ollydbg看到的x86的CISC指令集是同一个层面的东西)。作为其之前MIX语言的下一代,目前主要运用于作者本人著名巨著《计算机程序设计艺术》(The Art of Computer Programming)中。
补充阅读 高德纳
高德纳(英语:Donald Ervin Knuth,音译:唐纳德·尔文·克努斯,1938年1月10日-),出生于美国密尔沃基,著名计算机科学家,斯坦福大学计算机系荣誉退休教授。高德纳教授为现代计算机科学的先驱人物,创造了算法分析的领域,在数个理论计算机科学的分支做出基石一般的贡献。在计算机科学及数学领域发表了多部具广泛影响的论文和著作。1974年图灵奖得主。
高德纳所写的《计算机程序设计艺术》(The Art of Computer Programming)是计算机科学界最受高度敬重的参考书籍之一。他也是排版软件TeX和字体设计系统Metafont的发明人。此外,他还曾提出文学编程的概念,并创造了WEB与CWEB软件,作为文学编程开发工具。
来自维基百科
补充阅读 计算机程序设计艺术
《计算机程序设计艺术》(英语:The Art of Computer Programming),简称TAOCP,是美国计算机科学家高德纳(Donald Ervin Knuth)编著的关于计算机程序设计之七卷本著作。作者并因此获得美国计算机协会1974年图灵奖。
1962年,高德纳还是个研究生的时候就开始了程序设计的工作,在攻读博士期间,艾迪生韦斯利公司(Addison-Wesley)的顾问Richard Varga找他出书,因课业繁忙,一时没时间草稿。1963年高德纳获得加州理工学院数学博士学位,开始投入撰写工作。1968年,当时31岁的高德纳完成前六卷并首次出版,一口气写了三千多页,自此他计划写7卷。1999年底被《美国科学家》(American Scientist)期刊列为20世纪最佳12部学术专著之一,与狄拉克的“量子力学”、爱因斯坦的“相对论”、曼德布罗特的“分形论”、鲍林的“化学键”、罗素和怀特海德的“数学基础”、冯诺依曼和摩根斯坦的“博弈论”、维纳的“控制论”、伍德沃和霍夫曼的“轨道对称性”、费曼的“量子电动力学”等科学史上的重要著作并列必读经典。
总之这人这书都很牛叉就是了。这里批注一下,由于高德纳本人写这本书写的太长,书都是分批次出版的,而他本人关于MMIX的论述位于全书的1卷3章中。但是如果要买,实际上是需要单独购一本《MMIX:新千年的RISC语言》
为什么MMIX
实际上,现在实际投入使用的汇编语言,最广泛也是最出名的就是x86指令集。但是x86作为一个商业化的,长期使用的汇编语言,可能因为当时的硬件限制、或者为了保证前后兼容,多年维护下来,体系变得极为冗杂。对于技术人员倒是没什么大问题,但是对于初学者理解计算机汇编的本质却成为了极大的影响。
因此,高德纳构思出一种较为完美的,适用于教学的汇编语言MMIX。
另一方面,这也意味之,至少现在而言,MMIX没有实体机,仅仅是知识分子的YY而已ε=ε=ε=┏(゜ロ゜;)┛。
不过作为学习,MMIX是非常完美的。
理解了MMIX,再去理解其他的汇编语言,就有触类旁通的能力。
因此入门者走这样的路线:
从MMIX开始研究汇编语言——理解深刻后以这个为基础学习x86——走上逆向巅峰
MMIX语言入门关键
汇编语言,是和机器代码呈现映射关系的。在对汇编语言进行思考的时候,要一边想着硬件结构,一边进行汇编语句编程。下文2.1,2.2遵照这个逻辑进行介绍。
在现实的应用中,我们将高级语言直接编译成程序。程序员一般看不到汇编语言,而且也不需要关心。但是对于学习逆向,我们就不得不接触它。
硬件结构
MMIX是64位架构,因此寄存器64bit宽。有256个通用寄存器和32个特殊寄存器,同时还有2^64个8bit宽的内存单元(下列略称存储器)。
摘自TUM教材,Computertechnik.
组件单独介绍:
通用寄存器:通用寄存器用$作为前缀,数字编号,对应寄存器范围$0-$255。
常规的算数运算,都使用通用寄存器进行操作数提取和结果保留。也就是说,通用寄存器和逻辑运算单元(ALU)直接连接。
算术运算的案例:加法语句的通用逻辑就是将Y,Z两个寄存器中数字提取出来,相加并且放回X寄存器中。
特殊寄存器:特殊寄存器用r作为前缀,字母编号。
一般而言,特殊寄存器的作用是进行状态设置和状态检查。
状态设置的案例:我们设置特殊寄存器rA的第16-17位,可以指定当运算浮点数遇见误差时,计算器采取下列的不同方案:最近的数字(默认)/向正无穷方向近似/向0方向近似/向负无穷方向近似(为什么这四种状态请补习浮点数原理)
状态检查的案例:当整型运算产生上溢,对于MMIX也就是运算的结果超过了64位int所能容纳的上限时。特殊寄存器rA的第6位会被设置为1。当我们检查rA的第6位,也就等价于检查某一运算是否上溢。
存储器(内存单元):存储器地址用十六进制编码,在MMIX中十六进制数字前缀是#。
相比于寄存器,存储器的位宽较窄,但是量较大,一般用于保存数据。按照保存数据类型的不同,我们又将存储器分为不同的分区(Segment),如下图。各个分区的作用暂时不用管,之后我们在语言使用时会介绍。
摘自Das MMIX-Buch
MMIX语句
一个汇编语句,例如MMIX语句,会被编译器翻译成机器逻辑电路使用的0和1。
汇编语句按照一定顺序进行排列可以达成一定的功能,也就是写成了一个程序,每一个MMIX语句到底什么意思,是2.2.1的内容。
编译器作为翻译工具,过程和原理是2.2.2的内容。
MMIX语句编写
基本形态
再次强调这个原则,汇编语言和硬件一一对应,因此MMIX语句必定和硬件紧密相关。
MMIX语句的一般逻辑(也有特例):指定两个寄存器,进行某种操作,然后再将结论与第三个寄存器进行某种形式的传递。
因此,MMIX语句有着下面这样的形态:
ADD $3,$1,$2
ADD 是一种操作命令,用于指定操作的类型;
$3,$1,$2 连续的三个寄存器地址是操作数列表,用于指定操作的对象;
操作数列表的解读和使用由操作命令全权决定。
基本分类
对于新手,按照操作命令的作用,MMIX语句无非分成如下几种大类型:
算术语句:整数加减乘除,浮点数加减乘除,整数浮点数转换,位运算等等。
寄存器-存储器语句:将数据在寄存器和存储器之间倒腾的。
条件赋值/条件跳转语句:判断某个条件真假,根据结果决定是否跳转或者赋值。
无条件跳转语句:无条件跳转到某个地方。
如何寻找定义
好了,上面大概明白了MMIX语句该怎么看,那么我们可以信心满满地翻开下面这个网页,读懂每一个MMIX语句的功能了。
关于语句的详细信息,可以在http://mmix.cs.hm.edu/doc/instructions/index.html进行细节查询。
明白了上面两个原则,仍然不容易看懂上面网站上的信息,下面这些内容有助于理解。
直接操作数
我们会看到基本所有语句都被莫名其妙地写了两遍。例如下面这一系列条件赋值语句,操作命令一样,只有最后一点点不同。他们的区别在于后者含有一个直接操作数
对于同样一个操作命令,有两种变种
ADD $X,$Y,$Z
ADD $X,$Y,Z
后面这种,会将一个常数,而非一个寄存器作为对象进行处理。ADD $X,$Y,Z意味着,将$Y**寄存器**的数字直接加上常数Z,赋值给$X寄存器。按照性质,Z介于0到255。原因见后面的内容。
奇怪的定义
实际上英语不好影响着你的阅读,我没说错吧┑( ̄Д  ̄)┍。但是其中确实夹杂着奇怪的东西
s()那个部分是什么,左箭头又是什么?
s():意味着这个数字会被当作有符号整数看待,对应u()当作无符号整数看待。
左箭头:右边的结果赋值左边。
其他的就靠着自己想象力了,我相信你能猜出来( •̀ ω •́ )
帮助理解例程1(片段):
我们从官网上 查询到有下列语句
MUL $X,$Y,$Z 将寄存器$Y,$Z相乘,结果保存到$Z(暂不考虑溢出)
SUB $X,$Y,$Z 将寄存器$Y,$Z相减,结果保存到$Z(暂不考虑溢出)
ZSNN $X,$Y,Z 如果寄存器$Y中数字非负(**N**ot **N**egative) 那么将整数Z赋值给$X,否则将0赋值给$X
要求:三个数字a,b,c已经被放到了寄存器$1,$2,$3。他们是一个一元二次方程ax^2+bx+c=0(似乎论坛的$Latex$书写标签没有打开?)的系数。我们希望当一元二次函数有根的时候,$4为1,否则为0。我们使用$5,$6保存临时结果。
MUL $5,$2,$2
MUL $6,$1,$3
SUB $5,$6,$5
ZSNN $6,$5,1
基础拓展
相信读完了上面,你可以用MMIX语句进行基本的四则运算了,然后只要你肯读定义,你也可以搞位运算,条件赋值,条件跳转。你就可以实现大部分的程序了。
如果你再脑袋清晰一点,你也可以在寄存器和存储器之间倒腾数据。(没学会的,打道回府回去再看一遍QAQ,至少要明白,每个语句都是一个寄存器层面的操作)
但是这样的程序是跑不起来的,很遗憾,因为程序还需要进行一些前后补充。
伪语句:我们上面学到了,编译器将MMIX语句翻译成机器码。但是有些语句不能被翻译,它不算是MMIX程序的一部分,但是这些命令会直接给编译器造成影响。
标签:标签的作用是对一个语句取另一个名字。最为著名的是Main标签,它表示程序由此开始。其他的标签,主要运用在跳转或者寻找地址命令时,编译器帮你决定具体写什么。
为了让程序跑起来,需要一点硬件的约定,这个时候需要有之前那张图:存储器的分区图。
(再来一遍)
从存储器地址#0000 0000 0000 0000(十六进制)开始是Text_Segment。我们知道编译器将MMIX语句(你刚刚学会的那个)翻译成机器码(具体翻译过程见2.2.2),而这些机器码0或者1,会被保存在存储器的Text_Segment里面等待执行[附加1]。但是其中前100个,也就是#0-#99已经被预留了,因此MMIX程序都要在#100逐一写入。
从存储器地址#2000 0000 0000 0000(十六进制)开始是Data_Segment,它里面存储的就是程序运行时可以提取的数据。
LOC: 伪语句,让编译器从这个地方开始翻译或者书写内容。
所以例程1,需要前面补充上一句LOC,然后要在第一行写出Main标签。如果一个语句没有标签,第一个字符必须是空白字符来表示无标签。
LOC #100
Main MUL $5,$2,$2
MUL $6,$1,$3
SUB $5,$6,$5
ZSNN $6,$5,1
程序可以正确翻译,只不过很遗憾的是,上述语句并没有在$1,$2,$3里面保存a,b,c。实现这个功能涉及到的寄存器-存储器语句和基址在后面加深部分3讲解,这个地方就先不强行解释了。
[附加1]:你可能要问,为什么编译器翻译完了,程序直接写道存储器里面去?
更加清醒的人可能会问,我们平时写完程序编译好,出来的一个exe应该存储在大容量存储器,也就是通俗说的硬盘里面。而不是存储器,也就是通俗说的内存里面啊。
这个地方就是MMIX有些捉襟见肘的地方了。因为前面这个疑惑,是建立在我们平时使用的操作系统上面的,而操作系统有一个功能是管理程序的运行。平常程序都是存在硬盘里不执行,要用的时候拿出来放到内存里面。
但是MMIX本来就是个虚空创造出来的东西,根本没有操作系统,目前能够做的就是使用一个虚拟机将MMIX源代码读出来之后运行[见后文4“工具”]。因此我们为了在这个虚拟机里面让程序真正跑起来,必须要亲力亲为——把程序手动放到内存里面,然后手动把程序点开了运行,因此需要伪语句LOC和标签Main来让编译器帮忙。
翻译出来的机器码(见2.2.2),和前面这些辅助的伪语句和标签无关。
MMIX翻译
我们前面一直在念叨这句话:编译器将MMIX语句翻译成机器码。而2.2.1就在交你MMIX语句怎么看,怎么学,怎么写。这一节的侧重点就变成了怎么翻译。
翻译的基础流程
抛开上述所说的伪语句(因为他们根本就没法被翻译,而且和程序也无关),程序中每一个单独的MMIX语句,都可以被翻译成4*8bits的机器码命令。
如果你注意到前面那张硬件图左下角,其实他想说的就是这个翻译出来的机器码命令
正如前面所说,汇编语句和机器码一一对应。机器码分割开来的四段分别就是OP,X,Y,Z。分别对应操作命令和三个操作数列表。
操作数列表X,Y,Z直接一个一个翻译出来(不管Z是寄存器地址还是常数都一样)
操作命令和机器码的反应关系如下表:
先找到你需要的语句(例如找到CSN)
往左右两边看OP的第一位(6x)
大格子在上面向上看,下面向下看(CZN是6x大格子上面,因此往上看60或者61)
如果最后一个操作数Z是寄存器地址,看左边,操作数Z是常数,看右边;对于跳转语句也存在这个分支,左右意味着向后或者向前跳跃。跳跃具体参照加深部分3。
假设整个MMIX语句是
CSZ $2,$254,0
翻译十六进制结果
#6102FE00
MMIX执行最终流程
执行,前面编写和翻译的流程必须要完成。全过程如下。
1,你需要按照你的需求写出MMIX语句,得到源代码(.mms文件)。
2,你需要对源代码略加修饰,对编译器使用一些必要的伪语句,这样虚拟机才能够正确执行这段代码(.mms文件)。
3,编译器(控制台软件名叫mmix,详情见后文"工具")收到了伪语句,将MMIX语句翻译为机器码语句(.mmo文件)。前面还包含了伪代码的指示,从Main标签开始的语句,在运行的时候,挨个挨个从存储器#100向后书写。
4,虚拟机(控制台软件名叫mmixal,详情见后文"工具")开始运行程序。在完成伪语句的一些指示以后,从存储器的#100开始,四Byte一句开始读取并且执行语句,开始执行程序的主体。
5,#100开始的MMIX语句,也就是我们通常说的程序,会让寄存器进行一些操作,或者寄存器和存储器之间有数据流动。这样,一个程序就运行起来了。
(上面这张图用到了一些未经过介绍的伪语句和MMIX语句,如果你还不懂没有关系。他们是干什么的,会被怎么处理,你刚刚已经学会了)
所以程序的执行是严谨美丽的,尽管MMIX语句是一个”虚假的东西“,但是汇编语言的本质已经出来了。而且这个系统内部的各种参数都很工整,而且浑然一体,例如说(如果老手一眼就看出来了,这里给小白指出来一下):
1,寄存器有256个,也就是说,给寄存器编码的地址需要八位。而每一个机器码命令给一个操作数分配的位宽也是八位。
2,寄存器有64位,而这正好可以给存储器所有的地址编号,而且也确实绰绰有余。x86在32位时还发展出了物理地址扩展这种神奇的东西。
3,每一个机器码命令长度一样32bit。x86里面语句长度参差不齐。
加深部分
前面MMIX读懂了没有?有没有自己进行一些编写呢?理解到了MMIX的基本逻辑吗?
我之所以把很多东西写在后面,是发现了计算机学习的一个大问题:你要深刻理解一种编程语言,你就需要明白很多专业术语,理解他的体系。你要明白这些专业术语和体系,最好的讲解方式就是拿一些代码来说明他们。但是你会发现新手两个都没有,因此徘徊在"我不懂代码"和"我不懂原理"的深渊里,而且大量的教材都不管这一点,一开始就非常热情地给你塞很多东西。
因此我在第二章,使用最少的例程,最简单的语句,解释了MMIX从源代码到机器码的流程和逻辑,希望的是你能够理解MMIX这个东西的架构。也就是说,先在"理解他的体系"上面给自己搭建一个基础,让阅读变得没有障碍,自学变得流畅快活了一些。之后我们再来看一些看似基础但是背后难度颇大的部分。
有符号和无符号——溢出与不溢出的关系
对于同一个算数语句,常常会有两个分支:有符号的和无符号的。还是拿加法看,有ADD,与ADDU。而两者的主要区别有两个。
1,对于寄存器里面的内容进行解读和书写的不同。ADD会将$Y,$Z寄存器当作有符号整数(补码编码的64位int整数类型,如果你不懂这个请到其他地方补习计算机数字的保存),并且写入$X寄存器的,也是有符号整数类型。但是ADDU会将$Y,$Z寄存器当作无符号整数,也就是说,没有符号位或者补码编码。(对于出现的直接操作数Z永远都是无符号数)
2,对于溢出,两者处理不同。通常有符号的算数语句发生溢出后,会对特殊寄存器rA产生影响,无符号反之没有溢出。但是有一些,无符号的语句比有符号的语句操作更多:例如说无符号乘MULU,虽然不会对rA特殊寄存器标记上溢,但是会将所有的溢出位放到特殊寄存器rH里面,这样你就可以进行高位运算。
针对这个有如下的列表:(每一个语句单独定义是什么,需要你自己复习了,第二章已经教会你怎么取理解那些定义)
MMIX的四种字节单位
MMIX四种字节单位BYTE,WYDE,TETRA,OCTA,分别是1,2,4,8倍的BYTE大小。他们主要会在这些地方出现:
1,在伪语句中预留存储器空间时区分大小(见下面:伪语句加深)
2,在“寄存器-存储器”命令中决定读取/书写的方式。(见下面:奇妙的基址和寄存器-存储器命令之间的关系)
同时需要注意的是,我们既然涉及到了不同的大小单位,就要涉及到大端小端和对齐的问题了。
这里只补充两点
MMIX是大端书写的。
MMIX每个单位字节单位必须整除对齐。例如OCTA可以保存的地址只能是#00,#07,#10,#17。如果你要询问#02这个地址的OCTA,会被自动认为是在找#00上面的OCTA。
可以接受的对齐,摘自TUM教材Computertechnik
伪语句加深
我们除了学习伪语句LOC,还需要再学习五个语句,分别是BYTE,WYDE,TETRA,OCTA,GREG。
其中BYTE,WYDE,TETRA,OCTA意味着在当前定位的位置预留如上所述的空间大小,并且对其内部写入某个值。这个语句主要用于后面寄存器-存储器命令。
使用一次GREG,则会从$254开始向下预留一个寄存器,并且对其内部写入某个值。这个语句主要用于后面基址的功能中。
@标志表示当前的地址。
帮助理解例程2(片段):
我们现在使用以下上面五个伪语句。
LOC #2000 0000 0000 0000 *实际程序中请不要打空格!
GREG @
OCTA 255
BYTE 10
TETRA 2
GREG @
LOC #100
Main ADD ... 下面是程序主体
在程序主体开始执行之前,伪语句就做了如下的工作:从#2000 0000 0000 0000开始(Data_Segment的开头,为什么要这里开始,见前面的存储器分区),首先将#2000 0000 0000 0000这个地址保存到$254寄存器里面,然后预留一个写有255的OCTA,写有10的BYTE,写有2的TETRA。然后我们再将当前地址\#2000 0000 0000 0010保存到$253寄存器里面(不知道为什么当前地址是这里,回去看看对齐的原理!)。
Data_Segment目前的状况:
寄存器目前状况
奇妙的基址和寄存器-存储器命令之间的关系
我们之前说到,我们如果想要写入数据到寄存器里面,最常用的方式是使用寄存器-存储器命令。但是他们的定义看来有一些神奇,但是我们可以注意到的一个神奇东西是,所有的Load和Store命令(从存储器读取,保存到存储器),都是如下的三段式定义:
LDO $X,$Y,Z *将$Y+Z得到的结果对应的**存储器**地址那个地方的OCTA读取到**寄存器**$X里面。
其中$Y我们称之为**基址**,Z我们称之为**偏移量**(或者是$Z也行,一个是定值,一个是变量)。
一个作为基址的东西,我们需要随时运用它,因此他不能被销毁,应该成为全局变量。
在MMIX里面,我们规定从小到大$0开始算是本地变量,从大到小$255开始算是全局变量,但是操作系统预留下了$255,因此我们定义**基址**时,保存全局变量需要从$254开始向下保存。
MMIX,寄存器里面的本地和全局之分。本地寄存器的上界和全局寄存器的下界用特殊寄存器rL和rG标注,摘自TUM教材Computertechnik
而我们之前的那个伪语句加深里面的GREG就是干这一行的,他的目的就是保存一个新基址!
帮助理解例程3(片段):
我们把刚刚那个源代码倒腾下来,并且试用一下LDO。
LOC #2000 0000 0000 0000 *实际程序中请不要打空格!
GREG @
OCTA 255
BYTE 10
TETRA 2
GREG @
LOC #100
Main LDO $0,$254,0
LDB $1,$254,8
LDT $2,$254,12
运行的结果,刚刚伪语句定义的第一个OCTA255,被第一句话读入了$0寄存器中。然后是BYTE10读入$1,TETRA2读入$2。进入寄存器之后,他们都变成了64bit宽。
本地寄存器的结果图
对于绝对跳转,他们对于地址的指定都是基于基址的。例如GO,也需要在Text_Segment跳转目标前预留基址,实际上就大同小异了。
标签的用法
对于读取和跳转(不管是绝对还是相对的),我们都要手算位置关系(基址加上偏移)。这个简直就是人间地狱!所以我们可以使用标签让编译器给我们代劳。我们再把上面那个程序用标签的写法表达一遍。
帮助理解例程3(片段):
标签用法。
LOC #2000 0000 0000 0000 *实际程序中请不要打空格!
GREG @
A OCTA 255
B BYTE 10
C TETRA 2
GREG @
LOC #100
Main LDO $0,A
LDB $1,B
LDT $2,C
两者是等价的。但是注意:即使是使用了标签的写法,我们也不能够忽略基址,因为标签写法最终还是会被译作基址+偏移。如果实际编程中忘记了,那么会出现报错:没有足够近的基址。
MMIX的名字空间
用MMIX实现的函数调用
(未完待续)
从汇编语言看高级语言和系统
实际上我们在高级语言的编程中,背后对应的一定有汇编语言。对于已经会逆向的大神,这一点已经没有什么可以说的了。对于新手来说,我们可以从学习汇编语言明白更多的原理。
例如说平常递归函数背后藏着的,是局部变量构造起来的堆。
例如操作系统和程序之间的关系,无非就是操作系统调用程序——传递数据——程序运行——返回数据四个部分。这一点可以从MMIX之前的伪语句中得到一些理解(那些伪语句算是操作系统的一些必要的行为)。
etc,etc.
总之当你拿起汇编语言之后,才发现“原来平常学的语言还可以这样看啊”这种新鲜的感受。
从MMIX看x86
当你熟读MMIX,你会感叹着,啊,原来x86也就这像嘛。
mov 移动,add,sub加减,call和go有些相似之类的。
只不过x86有很多不适合新手的地方(或者叫做和MMIX相比糟糕的地方)
1,x86命令多(当然别人是CISC你也没啥办法)。而且每年都在加新的命令,新手短时间难记完。
2,这么多年,为了扩展新的指令,其语句长度也是参差不齐。这也导致了其机器码在硬件解码流程需要花费很多逻辑电路——这些东西本来不是必须的。
既然理解了MMIX,实际上x86也就好理解了。也就和我之前说的一样,在日后学习x86的日子里,你至少对于体系是清楚的,离开了“不会编程”和“不懂体系”的两难困境。
MMIX语言工具
看到这里,你是否有那么一点想要学习或者体验一下MMIX呢?可惜没有教材?可惜找不到资源?这里是一些干货。
参照信息类
MMIX的官网http://mmix.cs.hm.edu/index.html
MMIX特殊寄存器参照表http://mmix.cs.hm.edu/doc/registers.html
MMIX的语法参照表(英语)http://mmix.cs.hm.edu/doc/instructions/index.html
MMIX的语法参照表(德语)http://mmix.cs.hm.edu/doc/instructions.html
MMIX从语句到机器码对照表http://mmix.cs.hm.edu/doc/opcodes.html
编译工具类
MMIX控制台编译和虚拟机程序(Win)http://mmix.cs.hm.edu/exe/index.html
其中一个mmix就是前面念叨很久的编译器,负责将.mms源代码翻译成.mmo可执行文件;mmixal负责将.mmo在虚拟机上面进行运行,模拟程序被运行的过程。
MMIX可视化编译器(Win)http://mmix.cs.hm.edu/mmixvd/index.html
如果你都会用Linux了,我肯定假定你计算机有一定水平了,因此也就不用给你翻译网站的剩下部分了。
书籍类
Donald E. Knuth - The Art of Computer Programming, Volume 1, Fascicle 1_ MMIX -- A RISC Computer for the New Millennium-Addison-Wesley Professional (2005)
(高德纳本人的介绍)
Das MMIX-Buch
Ein praxisnaher Zugang zur Informatik
(德语补充资料,更加详细,贴近教学)