没有合适的资源?快使用搜索试试~ 我知道了~
首页80X86 IA32 汇编语言教程
80X86 IA32 汇编语言教程
5星 · 超过95%的资源 需积分: 10 37 下载量 84 浏览量
更新于2023-03-03
评论
收藏 629KB PDF 举报
我不想夸大或者贬低汇编语言。但我想说,汇编语言改变了20世纪的历史。与前辈相比,我们这一代编程人员足够的幸福,因为我们有各式各样的编程语言,我们可以操作键盘、坐在显示器面前,甚至使用鼠标、语音识别。我们可以使用键盘、鼠标来驾驭“个人计算机”,而不是和一群人共享一台使用笨重的继电器、开关去操作的巨型机。相比之下,我们的前辈不得不使用机器语言编写程序,他们甚至没有最简单的汇编程序来把助记符翻译成机器语言,而我们可以从上千种计算机语言中选择我们喜欢的一种,而汇编,虽然不是一种“常用”的具有“快速原型开发”能力的语言,却也是我们可以选择的语言中的一种。
资源详情
资源评论
资源推荐
第○章 写在前面
我不想夸大或者贬低汇编语言。但我想说,汇编语言改变了 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,并适当地用汇编取代部分高级语言代码。至少,汇编语言的知识可以告诉你一些有用的
东西,比如,你有多少个寄存器可以用。有时,手工的优化比编译器的优化更为有效,而且,你可以完全控制程序的实际行为。
我想我在罗嗦了。总之,在我们结束这一章之前,我想说,不要在优化的时候把希望完全寄托在编译器上——现实一些,再好的编译器也不可能
总是产生最优的代码。
简明 x86 汇编语言教程(2)-认识处理器
作者:司徒彦南 来源:互联网 酷勤网收集 2008-04-11
摘要
酷勤网
一般说来,处理器拥有对整个系统的所有总线的控制权。对于 Intel 平台而言,处理器拥有对数据、内存和控制总线的控制权,根据指令控
制整个计算机的运行。在以后的章节中,我们还将讨论系统中同时存在多个处理器的情况。处理器中有一些寄存器,可以保存特定长度的数据。
第二章 认识处理器
中央处理器(CPU)在微机系统处于“领导核心”的地位。汇编语言被编译成机器语言之后,将由处理器来执行。那么,首先让我们来了解一下处理
器的主要作用,这将帮助你更好地驾驭它。
典型的处理器的主要任务包括
从内存中获取机器语言指令,译码,执行
根据指令代码管理它自己的寄存器
根据指令或自己的的需要修改内存的内容
响应其他硬件的中断请求
一般说来,处理器拥有对整个系统的所有总线的控制权。对于 Intel 平台而言,处理器拥有对数据、内存和控制总线的控制权,根据指令控制整
个计算机的运行。在以后的章节中,我们还将讨论系统中同时存在多个处理器的情况。
处理器中有一些寄存器,这些寄存器可以保存特定长度的数据。某些寄存器中保存的数据对于系统的运行有特殊的意义。
新的处理器往往拥有更多、具有更大字长的寄存器,提供更灵活的取指、寻址方式。
寄存器
如前所述,处理器中有一些可以保存数据的地方被称作寄存器。
寄存器可以被装入数据,你也可以在不同的寄存器之间移动这些数据,或者做类似的事情。基本上,像四则运算、位运算等这些计算操作,都主
要是针对寄存器进行的。
首先让我来介绍一下 80386 上最常用的 4 个通用寄存器。先瞧瞧下面的图形,试着理解一下:
上图中,数字表示的是位。我们可以看出,EAX 是一个 32-bit 寄存器。同时,它的低 16-bit 又可以通过 AX 这个名字来访问;AX 又被分为高、低
8bit 两部分,分别由 AH 和 AL 来表示。
对于 EAX、AX、AH、AL 的改变同时也会影响与被修改的那些寄存器的值。从而事实上只存在一个 32-bit 的寄存器 EAX,而它可以通过 4 种不同的
途径访问。
也许通过名字能够更容易地理解这些寄存器之间的关系。EAX 中的 E 的意思是“扩展的”,整个 EAX 的意思是扩展的 AX。X 的意思 Intel 没有明
示,我个人认为表示它是一个可变的量 。而 AH、AL 中的 H 和 L 分别代表高和低 。
为什么要这么做呢?主要由于历史原因。早期的计算机是 8 位的,8086 是第一个 16 位处理器,其通用寄存器的名字是 AX,BX 等等;80386 是 Intel
推出的第一款 IA-32 系列处理器,所有的寄存器都被扩充为 32 位。为了能够兼容以前的 16 位应用程序,80386 不能将这些寄存器依旧命名为 AX、
BX,并且简单地将他们扩充为 32 位——这将增加处理器在处理指令方面的成本。
Intel 微处理器的寄存器列表(在本章先只介绍 80386 的寄存器,MMX 寄存器以及其他新一代处理器的新寄存器将在以后的章节介绍)
通用寄存器
下面介绍通用寄存器及其习惯用法。顾名思义,通用寄存器是那些你可以根据自己的意愿使用的寄存器,修改他们的值通常不会对计算机的运行
造成很大的影响。通用寄存器最多的用途是计算。
EAX
32-bit 宽
通用寄存器。相对其他寄存器,在进行运算方面比较常用。在保护模式中,也可以作为内存偏移指针(此时,DS 作为段 寄存器或
选择器)
EBX
32-bit 宽
通用寄存器。通常作为内存偏移指针使用(相对于 EAX、ECX、EDX),DS 是默认的段寄存器或选择器。在保护模式中,同样可以起
这个作用。
ECX
32-bit 宽
通用寄存器。通常用于特定指令的计数。在保护模式中,也可以作为内存偏移指针(此时,DS 作为 寄存器或段选择器)。
EDX
32-bit 宽
通用寄存器。在某些运算中作为 EAX 的溢出寄存器(例如乘、除)。在保护模式中,也可以作为内存偏移指针(此时,DS 作为段 寄
存器或选择器)。
上述寄存器同 EAX 一样包括对应的 16-bit 和 8-bit 分组。
用作内存指针的特殊寄存器
ESI
32-bit 宽
通常在内存操作指令中作为“源地址指针”使用。当然,ESI 可以被装入任意的数值,但通常没有人把它当作通用寄存器来用。DS
是默认段寄存器或选择器。
EDI
32-bit 宽
通常在内存操作指令中作为“目的地址指针”使用。当然,EDI 也可以被装入任意的数值,但通常没有人把它当作通用寄存器来用。
DS 是默认段寄存器或选择器。
EBP
32-bit 宽
这也是一个作为指针的寄存器。通常,它被高级语言编译器用以建造‘堆栈帧’来保存函数或过程的局部变量,不过,还是那句话,
你可以在其中保存你希望的任何数据。SS 是它的默认段寄存器或选择器。
注意,这三个寄存器没有对应的 8-bit 分组。换言之,你可以通过 SI、DI、BP 作为别名访问他们的低 16 位,却没有办法直接访问他们的低 8 位。
段寄存器和选择器
实模式下的段寄存器到保护模式下摇身一变就成了选择器。不同的是,实模式下的“段寄存器”是 16-bit 的,而保护模式下的选择器是 32-bit
的。
CS
代码段,或代码选择器。同 IP 寄存器(稍后介绍)一同指向当前正在执行的那个地址。处理器执行时从这个寄存器指向的段(实模
式)或内存(保护模式)中获取指令。除了跳转或其他分支指令之外,你无法修改这个寄存器的内容。
DS
数据段,或数据选择器。这个寄存器的低 16 bit 连同 ESI 一同指向的指令将要处理的内存。同时,所有的内存操作指令 默认情况
下都用它指定操作段(实模式)或内存(作为选择器,在保护模式。这个寄存器可以被装入任意数值,然而在这么做的时候需要小心
一些。方法是,首先把数据送给 AX,然后再把它从 AX 传送给 DS(当然,也可以通过堆栈来做).
ES
附加段,或附加选择器。这个寄存器的低 16 bit 连同 EDI 一同指向的指令将要处理的内存。同样的,这个寄存器可以被装入任意
数值,方法和 DS 类似。
FS
F 段或 F 选择器(推测 F 可能是 Free?)。可以用这个寄存器作为默认段寄存器或选择器的一个替代品。它可以被装入任何数值,方
法和 DS 类似。
GS
G 段或 G 选择器(G 的意义和 F 一样,没有在 Intel 的文档中解释)。它和 FS 几乎完全一样。
SS
堆栈段或堆栈选择器。这个寄存器的低 16bit 连同 ESP 一同指向下一次堆栈操作(push 和 pop)所要使用的堆栈地址。这个寄存器也
可以被装入任意数值,你可以通过入栈和出栈操作来给他赋值,不过由于堆栈对于很多操作有很重要的意义,因此,不正确的修改
有可能造成对堆栈的破坏。
* 注意 一定不要在初学汇编的阶段把这些寄存器弄混。他们非常重要,而一旦你掌握了他们,你就可以对他们做任意的操作了。段寄存器,或选
择器,在没有指定的情况下都是使用默认的那个。这句话在现在看来可能有点稀里糊涂,不过你很快就会在后面知道如何去做。
特殊寄存器(指向到特定段或内存的偏移量):
EIP
这个寄存器非常的重要。这是一个 32 位宽的寄存器 ,同 CS 一同指向即将执行的那条指令的地址。不能够直接修改这个寄存器的
值,修改它的唯一方法是跳转或分支指令。(CS 是默认的段或选择器)
ESP
这个 32 位寄存器指向堆栈中即将被操作的那个地址。尽管可以修改它的值,然而并不提倡这样做,因为如果你不是非常明白自己
在做什么,那么你可能造成堆栈的破坏。对于绝大多数情况而言,这对程序是致命的。(SS 是默认的段或选择器)
IP: Instruction Pointer, 指令指针
SP: Stack Pointer, 堆栈指针
好了,上面是最基本的寄存器。下面是一些其他的寄存器,你甚至可能没有听说过它们。(都是 32 位宽):
CR0, CR2, CR3(控制寄存器)。举一个例子,CR0 的作用是切换实模式和保护模式。
还有其他一些寄存器,D0, D1, D2, D3, D6 和 D7(调试寄存器)。他们可以作为调试器的硬件支持来设置条件断点。
TR3, TR4, TR5, TR6 和 TR? 寄存器(测试寄存器)用于某些条件测试。
最后我们要说的是一个在程序设计中起着非常关键的作用的寄存器:标志寄存器。
本节中部份表格来自 David Jurgens 的 HelpPC 2.10 快速参考手册。在此谨表谢意。
简明 x86 汇编语言教程(3)-使用寄存器
作者:司徒彦南 来源:互联网 酷勤网收集 2008-04-11
摘要
酷勤网
寄存器是处理器内部的一些保存数据的存储单元。仅仅了解这些是不足以写出一个可用的汇编语言程序的,但你已经可以大致读懂一般汇编
语言程序了(不必惊讶,因为汇编语言的祝记符和英文单词非常接近),因为你已经了解了关于基本寄存器的绝大多数知识。
2.2 使用寄存器
在前一节中的 x86 基本寄存器的介绍,对于一个汇编语言编程人员来说是不可或缺的。现在你知道,寄存器是处理器内部的一些保存数据的存储
单元。仅仅了解这些是不足以写出一个可用的汇编语言程序的,但你已经可以大致读懂一般汇编语言程序了(不必惊讶,因为汇编语言的祝记符
和英文单词非常接近),因为你已经了解了关于基本寄存器的绝大多数知识。
在正式引入第一个汇编语言程序之前,我粗略地介绍一下汇编语言中不同进制整数的表示方法。如果你不了解十进制以外的其他进制,请把鼠标
移动到这里。
汇编语言中的整数常量表示
十进制整数
这是汇编器默认的数制。直接用我们熟悉的表示方式表示即可。例如,1234 表示十进制的 1234。不过,如果你指定了使用其他数制,或者有凡
事都进行完整定义的小爱好,也可以写成[十进制数]d 或[十进制数]D 的形式。
十六进制数
这是汇编程序中最常用的数制,我个人比较偏爱使用十六进制表示数据,至于为什么,以后我会作说明。十六进制数表示为 0[十六进制数]h 或
0[十六进制数]H,其中,如果十六进制数的第一位是数字,则开头的 0 可以省略。例如,7fffh, 0ffffh,等等。
二进制数
这也是一种常用的数制。二进制数表示为[二进制数]b 或[二进制数]B。一般程序中用二进制数表示掩码(mask code)等数据非常的直观,但需要
些很长的数据(4 位二进制数相当于一位十六进制数)。例如,1010110b。
八进制数
八进制数现在已经不是很常用了(确实还在用,一个典型的例子是 Unix 的文件属性)。八进制数的形式是[八进制数]q、[八进制数]Q、[八进制数]o、
[八进制数]O。例如,777Q。
需要说明的是,这些方法是针对宏汇编器(例如,MASM、TASM、NASM)说的,调试器默认使用十六进制表示整数,并且不需要特别的声明(例如,
在调试器中直接用 FFFF 表示十进制的 65535,用 10 表示十进制的 16)。
现在我们来写一小段汇编程序,修改 EAX、EBX、ECX、EDX 的数值。
我们假定程序执行之前,寄存器中的数值是全 0:
?
X
H
L
EAX
0000
00
00
EBX
0000
00
00
ECX
0000
00
00
EDX
0000
00
00
正如前面提到的,EAX 的高 16bit 是没有办法直接访问的,而 AX 对应它的低 16bit,AH、AL 分别对应 AX 的高、低 8bit。
mov eax, 012345678h
mov ebx, 0abcdeffeh
mov ecx, 1
mov edx, 2
; 将 012345678h 送入 eax
; 将 0abcdeffeh 送入 ebx
; 将 000000001h 送入 ecx
; 将 000000002h 送入 edx
则执行上述程序段之后,寄存器的内容变为:
?
X
H
L
EAX
1234
56
78
EBX
abcd
ef
fe
ECX
0000
00
01
EDX
0000
00
02
那么,你已经了解了 mov 这个指令(mov 是 move 的缩写)的一种用法。它可以将数送到寄存器中。我们来看看下面的代码:
mov eax, ebx
mov ecx, edx
; ebx 内容送入 eax
; edx 内容送入 ecx
则寄存器内容变为:
?
X
H
L
EAX
abcd
ef
fe
EBX
abcd
ef
fe
ECX
0000
00
02
EDX
0000
00
02
我们可以看到,“move”之后,数据依然保存在原来的寄存器中。不妨把 mov 指令理解为“送入”,或“装入”。
练习题
把寄存器恢复成都为全 0 的状态,然后执行下面的代码:
mov eax, 0a1234h
mov bx, ax
mov ah, bl
mov al, bh
; 将 0a1234h 送入 eax
; 将 ax 的内容送入 bx
; 将 bl 内容送入 ah
; 将 bh 内容送入 al
思考:此时,EAX 的内容将是多少?[答案]
下面我们将介绍一些指令。在介绍指令之前,我们约定:
使用 Intel 文档中的寄存器表示方式
reg32 32-bit 寄存器(表示 EAX、EBX 等)
reg16 16-bit 寄存器(在 32 位处理器中,这 AX、BX 等)
reg8? 8-bit 寄存器(表示 AL、BH 等)
imm32 32-bit 立即数(可以理解为常数)
imm16 16-bit 立即数
剩余28页未读,继续阅读
suplch
- 粉丝: 0
- 资源: 2
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- ExcelVBA中的Range和Cells用法说明.pdf
- 基于单片机的电梯控制模型设计.doc
- 主成分分析和因子分析.pptx
- 共享笔记服务系统论文.doc
- 基于数据治理体系的数据中台实践分享.pptx
- 变压器的铭牌和额定值.pptx
- 计算机网络课程设计报告--用winsock设计Ping应用程序.doc
- 高电压技术课件:第03章 液体和固体介质的电气特性.pdf
- Oracle商务智能精华介绍.pptx
- 基于单片机的输液滴速控制系统设计文档.doc
- dw考试题 5套.pdf
- 学生档案管理系统详细设计说明书.doc
- 操作系统PPT课件.pptx
- 智慧路边停车管理系统方案.pptx
- 【企业内控系列】企业内部控制之人力资源管理控制(17页).doc
- 温度传感器分类与特点.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论2