简明x86汇编语言教程(1)

第○章 写在前面

我不想夸大或者贬低汇编语言。但我想说,汇编语言改变了20世纪的历史。与前辈相比,我们这一代编程人员足够的幸福,因为我们有各式各样的编程语言,我们可以操作键盘、坐在显示器面前,甚至使用鼠标、语音识别。我们可以使用键盘、鼠标来驾驭“个人计算机”,而不是和一群人共享一台使用笨重的继电器、开关去操作的巨型机。相比之下,我们的前辈不得不使用机器语言编写程序,他们甚至没有最简单的汇编程序来把助记符翻译成机器语言,而我们可以从上千种计算机语言中选择我们喜欢的一种,而汇编,虽然不是一种“常用”的具有“快速原型开发”能力的语言,却也是我们可以选择的语言中的一种。

每种计算机都有自己的汇编语言——没必要指望汇编语言的可移植性,选择汇编,意味着选择性能而不是可移植或便于调试。这份文档中讲述的是x86汇编语言,此后的“汇编语言”一词,如果不明示则表示ia32上的x86汇编语言。

汇编语言是一种易学,却很难精通的语言。回想当年,我从初学汇编到写出第一个可运行的程序,只用了不到4个小时;然而直到今天,我仍然不敢说自己精通它。编写快速、高效、并且能够让处理器“很舒服地执行”的程序是一件很困难的事情,如果利用业余时间学习,通常需要2-3年的时间才能做到。这份教材并不期待能够教给你大量的汇编语言技巧。对于读者来说,x86汇编语言"就在这里"。然而,不要僵化地局限于这份教材讲述的内容,因为它只能告诉你汇编语言是“这样一回事”。学好汇编语言,更多的要靠一个人的创造力于悟性,我可以告诉你我所知道的技巧,但肯定这是不够的。一位对我的编程生涯产生过重要影响的人曾经对我说过这么一句话:

写汇编语言程序不是汇编语言最难的部分,创新才是。

我想,愿意看这份文档的人恐怕不会问我“为什么要学习汇编语言”这样的问题;不过,我还是想说几句:首先,汇编语言非常有用,我个人主张把它作为C语言的先修课程,因为通过学习汇编语言,你可以了解到如何有效地设计数据结构,让计算机处理得更快,并使用更少的存储空间;同时,学习汇编语言可以让你熟悉计算机内部运行机制,并且,有效地提高调试能力。就我个人的经验而言,调试一个非结构化的程序的困难程度,要比调试一个结构化的程序的难度高很多,因为“结构化”是以牺牲运行效率来提高可读性与可调试性,这对于完成一般软件工程的编码阶段是非常必要的。然而,在一些地方,比如,硬件驱动程序、操作系统底层,或者程序中经常需要执行的代码,结构化程序设计的这些优点有时就会被它的低效率所抹煞。另外,如果你想真正地控制自己的程序,只知道源代码级的调试是远远不够的。

浮躁的人喜欢说,用C++写程序足够了,甚至说,他不仅仅掌握C++,而且精通STL、MFC。我不赞成这个观点,掌握上面的那些是每一个编程人员都应该做到的,然而C++只是我们"常用"的一种语言,它不是编程的全部。低层次的开发者喜欢说,嘿,C++是多么的强大,它可以做任何事情——这不是事实。便于维护、调试,这些确实是我们的追求目标,但是,写程序不能仅仅追求这个目标,因为我们最终的目的是满足设计需求,而不是个人非理性的理想。

这份教材适合已经学习过某种结构化程序设计语言的读者。其内容基于我在1995年给别人讲述汇编语言时所写的讲义。当然,如大家所希望的,它包含了最新的处理器所支持的特性,以及相应的内容。我假定读者已经知道了程序设计的一些基本概念,因为没有这些是无法理解汇编语言程序设计的;此外,我希望读者已经有了比较良好的程序设计基础,因为如果你缺乏对于结构化程序设计的认识,编写汇编语言程序很可能很快就破坏了你的结构化编程习惯,大大降低程序的可读性、可维护性,最终让你的程序陷于不得不废弃的代码堆之中。

基本上,这份文档撰写的目标是尽可能地便于自学。不过,它对你也有一些要求,尽管不是很高,但我还是强调一下。

学习汇编语言,你需要

胆量。不要害怕去接触那些计算机的内部工作机制。

知识。了解计算机常用的数制,特别是二进制、十六进制、八进制,以及计算机保存数据的方法。

开放。接受汇编语言与高级语言的差异,而不是去指责它如何的不好读。

经验。要求你拥有任意其他编程语言的一点点编程经验。

头脑。

祝您编程愉快!

第一章 汇编语言简介

先说一点和实际编程关系不太大的东西。当然,如果你迫切的想看到更实质的内容,完全可以先跳过这一章。

那么,我想可能有一个问题对于初学汇编的人来说非常重要,那就是:

汇编语言到底是什么?

汇编语言是一种最接近计算机核心的编码语言。不同于任何高级语言,汇编语言几乎可以完全和机器语言一一对应。不错,我们可以用机器语言写程序,但现在除了没有汇编程序的那些电脑之外,直接用机器语言写超过1000条以上指令的人大概只能算作那些被我们成为“圣人”的牺牲者一类了。毕竟,记忆一些短小的助记符、由机器去考虑那些琐碎的配位过程和检查错误,比记忆大量的随计算机而改变的十六进制代码、可能弄错而没有任何提示要强的多。熟练的汇编语言编码员甚至可以直接从十六进制代码中读出汇编语言的大致意思。当然,我们有更好的工具——汇编器和反汇编器。

简单地说,汇编语言就是机器语言的一种可以被人读懂的形式,只不过它更容易记忆。至于宏汇编,则是包含了宏支持的汇编语言,这可以让你编程的时候更专注于程序本身,而不是忙于计算和重写代码。

汇编语言除了机器语言之外最接近计算机硬件的编程语言。由于它如此的接近计算机硬件,因此,它可以最大限度地发挥计算机硬件的性能。用汇编语言编写的程序的速度通常要比高级语言和C/C++快很多--几倍,几十倍,甚至成百上千倍。当然,解释语言,如解释型LISP,没有采用JIT技术的Java虚机中运行的Java等等,其程序速度更无法与汇编语言程序同日而语 。

永远不要忽视汇编语言的高速。实际的应用系统中,我们往往会用汇编彻底重写某些经常调用的部分以期获得更高的性能。应用汇编也许不能提高你的程序的稳定性,但至少,如果你非常小心的话,它也不会降低稳定性;与此同时,它可以大大地提高程序的运行速度。我强烈建议所有的软件产品在最后Release之前对整个代码进行Profile,并适当地用汇编取代部分高级语言代码。至少,汇编语言的知识可以告诉你一些有用的东西,比如,你有多少个寄存器可以用。有时,手工的优化比编译器的优化更为有效,而且,你可以完全控制程序的实际行为。

我想我在罗嗦了。总之,在我们结束这一章之前,我想说,不要在优化的时候把希望完全寄托在编译器上——现实一些,再好的编译器也不可能总是产生最优的代码。

时间: 2024-12-17 06:45:52

简明x86汇编语言教程(1)的相关文章

简明x86汇编语言教程(7)

5.0 编译优化概述 优化是一件非常重要的事情.作为一个程序设计者,你肯定希望自己的程序既小又快.DOS时代的许多书中都提到,"某某编译器能够生成非常紧凑的代码",换言之,编译器会为你把代码尽可能地缩减,如果你能够正确地使用它提供的功能的话.目前,Intel x86体系上流行的C/C++编译器,包括Intel C/C++ Compiler, GNU C/C++ Compiler,以及最新的Microsoft和Borland编译器,都能够提供非常紧凑的代码.正确地使用这些编译器,则可以得

简明x86汇编语言教程(5)

3.4 串操作 我们前面已经提到,内存可以和寄存器交换数据,也可以被赋予立即数.问题是,如果我们需要把内存的某部分内容复制到另一个地址,又怎么做呢? 设想将DS:SI处的连续512字节内容复制到ES:DI(先不考虑可能的重叠).也许会有人写出这样的代码: NextByte: mov cx,512 mov al,ds:[si] mov es:[di],al inc si inc di loop NextByte ; 循环次数 我不喜欢上面的代码.它的确能达到作用,但是,效率不好.如果你是在做优化,

简明x86汇编语言教程(6)

4.0 利用子程序与中断 已经掌握了汇编语言?没错,你现在已经可以去破译别人代码中的秘密.然而,我们还有一件重要的东西没有提到,那就是自程序和中断.这两件东西是如此的重要,以至于你的程序几乎不可能离开它们. 4.1 子程序 在高级语言中我们经常要用到子程序.高级语言中,子程序是如此的神奇,我们能够定义和主程序,或其他子程序一样的变量名,而访问不同的变量,并且,还不和程序的其他部分相冲突. 然而遗憾的是,这种"优势"在汇编语言中是不存在的. 汇编语言并不注重如何减轻程序员的负担:相反,汇

简明x86汇编语言教程(4)

第三章 操作内存 在前面的章节中,我们已经了解了寄存器的基本使用方法.而正如结尾提到的那样,仅仅使用寄存器做一点运算是没有什么太大意义的,毕竟它们不能保存太多的数据,因此,对编程人员而言,他肯定迫切地希望访问内存,以保存更多的数据. 我将分别介绍如何在保护模式和实模式操作内存,然而在此之前,我们先熟悉一下这两种模式中内存的结构. 3.1 实模式 事实上,在实模式中,内存比保护模式中的结构更令人困惑.内存被分割成段,并且,操作内存时,需要指定段和偏移量.不过,理解这些概念是非常容易的事情.请看下面

X86汇编语言总结

下载地址:点击打开下载链接 AX.BX.CX.DX一般用来存放数据 [BX].[BP].[SI].[DI]中一般存放着某个段寄存器的偏移地址,默认情况下,[BX]中存放着数据段(DS)的偏移地址,[BP]中存放着栈段(SS)的偏移地址(功能和SP类似),其中BX只能和SI.DI组合,BP只能和SI.DI组合,SI.DI间是不能组合的 Loop指令一般搭配着CX寄存器使用,每循环一次,CX寄存器中的值减少1 执行PUSH指令时,SP-2,执行POP时,SP+2 个人的一点总结:压栈时,先减后压:出

HTTP Headers简明易懂的教程

本文系统的对HTTP Headers进行了简明易懂的阐述,我仅稍作笔记. 什么是HTTP Headers HTTP是"Hypertext Transfer Protocol"的所写,整个万维网都在使用这种协议,几乎你在浏览器里看到的大部分内容都是通过http协议来传输的,比如这篇文章. HTTP Headers是HTTP请求和相应的核心,它承载了关于客户端浏览器,请求页面,服务器等相关的信息. 示例 当你在浏览器地址栏里键入一个url,你的浏览器将会类似如下的http请求:GET /t

ASP.NET与MySQL数据库简明图示入门教程

在ASP时代,如果我们要建立一个数据库驱动的web站点,那么你可以选择环很多钱的微软SQLSERVER数据库或者选择要花很多时间来寻找达到性能和稳定性统一的ACCESS数据库,但在.NET时代你有另一种选择,那就是:MySQL数据库 什么是MySQL数据库? MySQL数据库是一种开放源代码的数据库,通过获得授权来保持源代码的官方支持,同时可以自由修改源代码,目前许多公司和组织都采用了这种数据库.对此详细信息您可以访问MySQL的官方站点. 第一步下载和安装 与大多数软件一样,首先是得到并安装m

ASP.NET与MySQL数据库简明图示入门教程_实用技巧

作者: CRYSTAL编译 在ASP时代,如果我们要建立一个数据库驱动的web站点,那么你可以选择环很多钱的微软SQL SERVER数据库或者选择要花很多时间来寻找达到性能和稳定性统一的ACCESS数据库,但在.NET时代你有另一种选择,那就是:MySQL数据库 什么是MySQL数据库? MySQL数据库是一种开放源代码的数据库,通过获得授权来保持源代码的官方支持,同时可以自由修改源代码,目前许多公司和组织都采用了这种数据库.对此详细信息您可以访问MySQL的官方站点. 第一步 下载和安装 与大

使用GCC和GNU Binutils编写能在x86实模式运行的16位代码

使用GCC和GNU Binutils编写能在x86实模式运行的16位代码 不可否认,这次的标题有点长.之所以把标题写得这么详细,主要是为了搜索引擎能够准确地把确实需要了解GCC生成16位实模式代码方法的朋友带到我的博客.先说一下背景,编写能在x86实模式下运行的16位代码,这个话题确实有点复古,所以能找到的资料也相应较少.要运行x86实模式的程序,目 前我知道的只有两种方式,一种是使用DOS系统,另一种是把它写成引导扇区的代码,在系统启动时直接运行.很显然,许多讲自己实现操作系统的书籍都会讲到