ThomasvH 发表于 2020-2-22 09:16

【笔记】适合新手理解汇编语言MMIX-原创笔记-为你的逆向学习打下基础

本帖最后由 ThomasvH 于 2020-2-22 13:23 编辑

# 前言
## 创作动机
最近一段时间在和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软件,作为文学编程开发工具。
>!(https://upload.wikimedia.org/wikipedia/commons/4/4f/KnuthAtOpenContentAlliance.jpg)
>来自维基百科
>
>---
>**补充阅读 计算机程序设计艺术**
>《计算机程序设计艺术》(英语: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语言》*
>![一大家子](https://www-cs-faculty.stanford.edu/~knuth/taocp.jpg)
## 为什么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(暂不考虑溢出)
>>ZS**NN** $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
(德语补充资料,更加详细,贴近教学)

ThomasvH 发表于 2020-2-22 16:40

☆木木可可★ 发表于 2020-2-22 03:37
好复杂,感觉再这样下去,真的得发明计算机自己写程序了,然后到未来。。。我们人类完全依赖计算机的时候, ...

实际上汇编是最早出现的哦,在高级语言(C,Java等等)都还没有出现的时候,汇编语言就是唯一的编程方式。所以这个算是“向前回顾”,“回望历史”的内容,不算什么高端东西。

ThomasvH 发表于 2020-2-22 18:51

本帖最后由 ThomasvH 于 2020-2-22 11:52 编辑

$ax^2+bx+c=0$
$ax^2+bx+c=0$
ax^2+bx+c=0
$ax^2+bx+c=0$
ax^2+bx+c=0
$ax^2+bx+c=0$
@Hmily H大大,论坛Latex功能用不起啊?你之前那个MD参考帖子里面也没显示出来呢?

vethenc 发表于 2020-2-22 10:15

不明觉厉,点赞好文。

小白1只吖 发表于 2020-2-22 10:34

汇编的都是大佬

☆木木可可★ 发表于 2020-2-22 10:37

好复杂,感觉再这样下去,真的得发明计算机自己写程序了,然后到未来。。。我们人类完全依赖计算机的时候,我们就会变成人工智能的奴隶了吧。。。黑客帝国。。。{:1_918:}

=伊= 发表于 2020-2-22 10:39

楼主好厉害!新手膜拜大佬

BlovedCQ 发表于 2020-2-22 14:30

支持 知识分享,感谢楼主

Hmily 发表于 2020-2-23 17:09

ThomasvH 发表于 2020-2-22 18:51
$ax^2+bx+c=0$
$ax^2+bx+c=0$
ax^2+bx+c=0


{:1_907:}不好意思,那个插件没买不支持,帮助是从插件作者那复制过来的,我改下。

bjxiaoyao 发表于 2020-2-25 07:56

学习了,汇编语言最基础
页: [1] 2
查看完整版本: 【笔记】适合新手理解汇编语言MMIX-原创笔记-为你的逆向学习打下基础