首页 > 代码库 > 汇编语言

汇编语言

  为了操作系统,再一次看汇编语言(王爽),汇编这东西说着说着就到硬件了,类似于群雄割据,反正再出个什么协议或者规范什么的太晚了...
  我挺喜欢这样的,偶尔看看大神吵架简直就是人生一大乐趣,当然不管咋样,我就打个酱油,为自己做做笔记,说道做笔记,在学校的习惯,做笔记就是全篇复制,没有自己的思想,抓不住重点,这种习惯也让我多次放弃了写博客的习惯,关键不是写博客,做笔记,而是逼迫自己去思考,置于烤到了什么...who cares

=================================

王爽〔汇编语言〕教程批判(转)

我在百度贴吧里面, 惊讶地发现有学生正在编写"B800直接写屏"的程序作为练习. 这种落后于时代达30年之久的技术, 怎么会有学校教授呢? 随后我发现, 这些程序居然来源于清华大学王爽教授的[汇编语言]教程第二版. 于是我感到好奇: 为什么王爽选择了这样一些落后于时代达30年之久的技术进行传授.

我下载了王爽的[汇编语言]第二版. 我的第一感觉, 这本书既然讲到了"B800直接写屏"技术, 它应该产生于1985年左右的时代. 然而我却惊讶地发现: 这本教程竟然写作于2008年! 王爽教授应该更新他的知识图谱. 2008年的CPU市场的情形究竟是怎样呢? 8086退出市场已经有20年了, 市面上已经不再有纯粹意义上的8086, 只有使用硬件模拟8086指令的机器. 这种硬件模拟跟软件模拟是没有什么实质区别的, 你在手机上也可以模拟8086的硬件动作, 只不过手机上是ARM指令集, 所以只能软件模拟, 并不能硬件模拟, 效率比硬件模拟低了12倍, 对于教学用的只有几十行的汇编代码而言, 根本看不出有什么差别. 你选择一个, 已经退出市场达20年的CPU的汇编语言作为教材, 到底是什么意思呢?

然后我们检查你的选用依据, 发现你解释为"常用而又结构简洁", 喔噻! 你知道"常用"这句话是什么意思吗?

我来告诉你什么叫"常用": 你家里面有一台桌面电脑吧? 你的桌面电脑有一个键盘吧? 这个键盘里面所使用的CPU是8047. 你为什么不认为, 8047是"常用"的CPU呢? 你究竟是根据什么来定义这个"常用"呢? 你的键盘里面有一个CPU, 你的鼠标里面也有一个CPU, 你的主板上面有一个CPU风扇, 那个控制CPU风扇的器件也是一个CPU, 你的显卡有一个风扇, 那个控制显卡风扇的器件也是一个CPU; 你的机箱里面有一个电源, 那个电源里面也有一个CPU - 真正常用的CPU是单片机的CPU, 你为什么没有选择某种单片机的CPU来进行讲解呢?

你的第二个选用依据是"结构简洁". 喔噻! 你难道不知道8086是 CISC机器吗? 第一次听到有人说, CISC机器结构简洁. 你是根据什么来做出这一判断的呢? 与什么来做比较呢? 与Z80来做比较吗? Z80是4个寄存器的寄存器组, 8086也是4个寄存器, 它们的复杂度似乎相当啊! 与ARM来做比较吗? ARM是16个寄存器的寄存器组, 8086仅仅只有4个寄存器, 你是根据这一点来判断8086"结构简洁"对吗? 在你眼里, 寄存器组越小, 结构就越简洁对吧?

从硬件结构的角度来说, 8086是 CISC机器, 有一个极其庞大的指令集, 庞大的指令集同时即意味着庞大的译码机构, 所以8086的硬件结构非常的复杂, 别的不说, 首先译码机构就很复杂; 从软件结构的角度上来说, 8086有着丰富的寻址方式, 而RISC机器(比如ARM)则是 Load/Store 模式, 只有少数几种寻址方式, 软件结构更为简洁. 事实上, Intel公司从未说过自己的CPU结构简洁, 从来都是吹嘘自己的CPU功能强大. 功能强大即意味着结构复杂, 无论从想象的角度还是事实上, 都是如此.

王爽教授之所以认为8086结构简洁, 实际上是受到了流行因素的影响. 8086系列是桌面系统的主流CPU, 占有90%的市场, 于是王爽教授把自己的眼光局限在8086系列上面, 并且仅仅只在8086, 80286, 80386, 80486, 80586, 80686之间进行比较, 然后认为8086比较简单, 于是就选择了8086, 然后就把8086的这种简单, 说成是简洁.

8086远远谈不上简洁, 相反, 它是逻辑上最为复杂的系统, 并且这种复杂是一种不必要的复杂. 8086机器是一种16位机器, 机器字长的限制, 使得8086难以寻址超过64K的地址. 为了解决这一问题, 8086引进了一种逻辑上非常丑陋的体系架构, 即CS, DS, ES段寄存器. 不可否认的是, 这种临时性的解决方案, 获得了巨大的成功,并且使得8086成为了最畅销的16位CPU, 然而, 一旦发展出32位的机器, 这种解决方案的必要性, 也就消失了. 我问你: 在当代的计算机生产序列里面, 有依旧使用中的8位CPU, 比如你电脑键盘里面的8047, 有依旧使用着的32位CPU, 比如手机和桌面电脑里面的主CPU, 但是16位的CPU在哪里? 它已经从生产序列中消失了, 对吧? 它只是一种临时性的解决方案, 作为一种过渡形态, 存在了短暂的时间, 然后消失于历史长河. 之前没有它的影子, 因为人们还没有能力制造它, 之后也没有它的影子, 因为人们已经不再需要它, 它就是一种历史过渡, 等历史渡过了那个时刻, 它就只有消失的份.

当代程序员从不显式地操作CS, DS, ES段寄存器, 他们仅仅简单地设置为平板(flat)模式, 然后操作其它的设备. 然而真实的Windows操作系统从不真正工作在平板模式, 而是使用这些程序员所从不使用的CS, DS, ES段寄存器, 去实现一些非常复杂的高级功能. 你的学生从参加工作的第一天起, 直到退休的那个时候, 从未对CS, DS, ES段寄存器进行过任何一次显式操作, Windows系统也不允许他们对于段寄存器进行操作. 一旦他们操作了这些段寄存器, Windows会终止程序的运行, 并且认为, 这一程序存在有某种异常.

既然你的学生, 一辈子都不会操作CS, DS, ES段寄存器, 难道你不认为, 有必要略去针对CS, DS, ES的任何介绍吗? 而, 一旦略去了对于CS, DS, ES的任何介绍, 你难道不认为, 80386实际上, 比8086更为简单吗? 8086本来就是一种过渡形态, 为了克服16位的局限, 它不必要地复杂. 你把这种不必要的复杂, 引进了[汇编语言]教程里面.

一旦你把8086汇编语言, 改为80386汇编语言, 你会发现: 你的整个[汇编语言]教程, 可以省略好几个章节. 既然你选择了, 并不去介绍完整的8086指令集, 你当然也可以选择, 并不介绍80386里面的CS, DS, ES段寄存器. 反正你的学生, 一辈子也用不上(除非他去做操作系统, 那种机会很少的). 这样一来, 你的整个[汇编语言]教程, 将会多余好几个课时, 可以考虑, 到底应该增加些什么内容.

首先我们来考虑, 传统CPU到底是什么样子. 传统CPU, 大致上由 ALU, 寄存器组, 译码部件, 取指部件这几大部分所组成. 其中译码部件和取指部件被认为是"软件透明的". 从软件的角度, 看不见针对这些部件的操作, 虽然实际上, 它们确实操作着这些部件. 比如说你执行 jmp Label_1; 的时候, 你实际上操作了取指部件, 但是软件看不见这种操作, 软件看见的仅仅是, 程序的执行跳到了 Lable_1 所在的地址. 既然软件看不见, 就可以视作不存在. 所以, 从软件的角度来说, 传统CPU是由[ALU + 寄存器组]所组成的架构, 还有一些附属的配件, 主要是IO和中断.

当代CPU远比传统CPU复杂, 主要包括几个方面:
1. 传统CPU, [ALU + 寄存器组]架构;
2. 协处理器部件: 浮点协处理器(80387), MMX/SSE;
3. 高速缓存部件(Cache);
4. 存储体管理单元(MMU);
5. 多核架构部件(SMP).

其中MMU和SMP主要是由操作系统管理的. 你的学生里面, 只有极少数, 毕业后会加入操作系统公司, 那些公司都有专门的培训, 所以, 这些内容都没有必要在大学课堂上讲授.

浮点协处理器(80387)通常是由编译器自动处理, 你的学生里面, 也只有极少数会加入编译器公司, 它们也有培训, 所以也没有必要介绍.

Cache在80386和80486里面都是透明的, 后来虽然提供了有限的操作可能, 但是主要是由操作系统管理, 所以也没必要介绍.

所以, 可以考虑增加的课程为: MMX/SSE.

再考虑到, 汇编语言的传统应用场景有两个:
1. 再单片机编程里面, 使用汇编语言, 直接操作硬件.
2. 在高级语言编程中, 专门针对某些额外影响性能的关键函数, 使用汇编语言改写, 进行代码优化.

使用汇编语言直接操作硬件方面, 由于单片机领域已经发展出了一种专用的C语言, 称作C51, 这种专用的C语言, 特别适合于直接操作硬件. 所以, 使用汇编语言直接操作硬件的应用场景已经大为缩小. 所以, 当代汇编语言最主要的应用场景就是代码优化, 尤其使用MMX/SSE所进行的代码优化. 所以, 应该考虑增加MMX/SSE的讲解和应用实例.

汇编语言