Version 1.02
Copyright@2005,Jeff Huang.All rights reserved
Translator:fqh 2005.7.10
|
目录
介 绍 ……………………………………………………………………………2
为什么选用汇编语言 …………………………………………………………2
为什么选择Windows系统……………………………………………………2
Ⅰ开始学习之旅 ……………………………………………………………….…3
编译器 ………………………………………………………………………3
编辑器 …………………………………………………………………………3
Ⅱ第一个程序 ……………………………………………………………………4
控制台程序 ……………………………………………………………………4
窗体程序 ………………………………………………………………………6
ADDR 与 OFFSET ………………………………………………………6
Ⅲ汇编基础…………………………………………………………………………7
cpu寄存器 ……………………………………………………………………7
指令集基础 ……………………………………………………………………8
Push 和 Pop…………………………………………………………………8
Invoke ……………………………………………………………………9
程序例子 ………………………………………………………………………9
IV. 窗体程序基础…………………………………………………………………10
预备知识………………………………………………………………………10
宏……………………………………………………………………………10
过程…………………………………………………………………………10
变量…………………………………………………………………………10
一个简单的窗体程序…………………………………………………………11
IV. 深入汇编和系统………………………………………………………………13
字符串操作……………………………………………………………………13
文件管理………………………………………………………………………13
存储…………………………………………………………………………14
程序例子……………………………………………………………………14
控制……………………………………………………………………………15
附加资源 …………………………………………………………………………16
互联网………………………………………………………………………16
书籍…………………………………………………………………………16
MASM32……………………………………………………………………16
MSDN………………………………………………………………………16
新闻组………………………………………………………………………16
IRC …………………………………………………………………………16
“This is for all you folks out there,who want to learn the magic art of Assembly programming”
-MAD
介 绍
我最近才开始学习windows系统汇编语言编程,这个教程是我在学习汇编语言的过程中写下来的。我阅读大量的在线教程、书本,以及通过新闻组以及IRC通讯工具请问他人,本人就是通过这些方式学习汇编语言的。互联网上有很多的汇编编程的教程,但这些教程只是侧重于X86汇编。因为这些教材都假定读者已经掌握了高级编程语言以及基本的计算机系统知识。
为什么选用汇编语言?
汇编语言具有若干的特色,使得在某此情况下,汇编语言是一种很好的选择。
1 快速 汇编语言程序运行的速度比高级语言程序要快。通常,要求运行效率高的子程序是用汇编语言编写的。
2 强大 运用汇编语言,你能得到不受限制的权力。相对的,高级语言则有种种限制,在实现某些特定的要求时变得困难。
3 体积小 汇编语言程序通常比其他语言程序要小得多。这种特性在空间有限的情况下是非常有用的。
为什么选择Windows系统?
在任何操作系统和处理器模式下,都可以编写相应的汇编语言程序的。但是当前,多数人在使用基于x86处理器的Windows系统,所以从编写运行于此种环境下的程序开始我们的教程。一旦一种汇编语言的基础知识掌握了,我们就会很容易写出在其他运行环境下汇编程序。
Ⅰ开始学习之旅
编写汇编程序,我们必须具备一些工具,它们是编译器以及编辑器。我们选择了一些能胜任这些工作的运行于Windows系统的工具如下。
编译器
编译器能把写下的汇编程序代码转换成机器码。通常,它附带有一个连接器。连接器用来连接可编译文件并从中生成可执行文件。Windows系统的可执行文件是以.exe为后缀的。下面给出一些流行的编译器:
1 MASM 这个编译器是本教程所选用的,在学习本教程的过程中,你可以使用它。它原先由微软公司开发,现在被包括在MASM32v8程序包内了。MASM32v8程序包还包括了其他的工具。你可以从这个网址得到它:http://www.masm32.com/.
注意:教程中有一些指令和宏指令,只有在MASM编译器才是有效的,所以强烈建议您从开始学习时选用MASM。 |
2. TASM 这是另一个受欢迎的编译器。由Borland公司开发,现在依然是个商业软件,所以你不能免费地获取到它。
3. NASM 一个免费开放源码的编译器,它也能在其他系统平台上使用。它可以从这个网址获取到http://sourceforge.net/projects/nasm/ 记住
编辑器
编辑器是在编译前编写程序代码的软件。编辑器可以个人自由选择。现在在很多种编辑器,你可以试用一下它们并选择一种你喜欢的。
1 Notepad 记事本,Windows系统自带的。虽然它缺少很多功能,但它使用简便。
2 Visual Studio 它不是免费的编辑器,但它出色的语法高亮显示功能能让你的代码更易于阅读。
3. 其他 – 还有很多其他的编辑器,在些不一一列出它们的名字。其中一些很受欢迎:
a. Ultraedit (我个人最喜欢的e) http://www.ultraedit.com/
b. Textpad http://www.textpad.com/
c. VIM http://www.vim.org/
d. Emacs http://www.gnu.org/software/emacs/emacs.html
e. jEdit http://www.jedit.org/
Ⅱ第一个程序
现在我们有了自己的工具,打开你的文本编辑器,跟着下面的介绍,开始学习编程吧。这是世上最普通的程序,“Hello World”程序。
控制台程序
控制台程序是运行在系统控制台的(也就大家所知的命令行)。为创建这个程序,首先粘贴下面的代码到你的文本编辑器上,并保存为文件“hello.asm”。
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
.data
HelloWorld db "Hello World!", 0
.code
start:
invoke StdOut, addr HelloWorld
invoke ExitProcess, 0
end start
现在,通过开始菜单,点“运行…”选项,输入“cmd”(没有引号)并回车,就能进入到命令行。接着在cmd下转到保存有”hello.asm”的目录,输入"\masm32\bin\ml /c /Zd /coff hello.asm"。期望编译器不会提示错误,你的程序能被正确编译!然后,我们还得连接它,所以接着输入"\masm32\bin\Link /SUBSYSTEM:CONSOLE hello.obj"。祝贺你!你已经成功编译了第一个汇编语言程序。在文件夹里出现了一个中Hello.exe的文件。在命令行下打"hello"来运行你的程序。它会输出"Hello World!"。可见,为了显示"Hello World!",我们只要编写很少的代码就可以了。
这些代码都起了什么作用呢?让我们一行一行地看下去。
.386
这条指令的作用是告知编译器使用.386指令集。当前,几乎没有处理器使用比.386更老的指明令集了。我们还可以选择使用.486.或586,但是.386是兼容性最好的指令集。
.model flat, stdcall
.MODEL 是一条指定你程序的内存模式的汇编指令。Flat是一种方便的系统程序模式,因为在这种模式下不再区分远指针(far)和近指针(far)。Stdcall 是一种系统函数传递参数的方法,它意味着你得以从右到左的顺序传递你的参数。
option casemap :none
强制你的程序代码大小写敏感,这意味着Hello和hello被看做不同的。很多高级编程语言同样是大小写敏感的,所以这是个编程的良好习惯。
include \masm32\include\windows.inc
include \ masm32\include\kernel32.inc
include \masm32\include\masm32.inc
这是系统程序必需的包含文件。windows.inc通常必须包含的,因为它包含了Win32 API常量和定义的声明。kernel32.inc包含了我们所使用的ExitProcess函数。masm32.inc包含有StdOut函数。StdOut函数不是Win32函数,它是MASM32v8新增进去的。
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
函数依赖库,基于这个目的,这些库得包含进去。
.data
程序中所有初始化的数据必须放在这条指令下面。此外,还有别的指令比如.data?和.const。它们分别位于未初始化数据和常量的前面,但是,在我们的”Hello World”程序中并没有用到它们。
HelloWorld db "Hello World!", 0
db代表“字节”,并声明HelloWorld为一个字符串。"Hello World!"后面跟着一个”NULL”字母,这是因为ANSI字符串必须以NULL结尾。
.code
这代表程序代码段的开始。
start:
你程序的代码位于这个标号的后面,但位于” end start”前面。
invoke StdOut, addr HelloWorld
Invoke调用一个函数及其参数,addr HelloWorld位于它后面。这一行所做的是传递"Hello World!"的地址和调用StdOut。注意StdOut函数只是在MASM32中有效的,它是一个调用其它函数来输出文件的宏。在别的编译器里,你得使用更多的代码并要用到win32函数WriteConsole.。
invoke ExitProcess, 0
显而易见,它传递参数0到ExitProcess函数,从而退出进程。
窗体程序
我们也可以编写一个有窗体版本的“Hello World”程序。粘贴下面文本到你的文件编辑器里并保存为文件"hellow.asm".
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
.data
HelloWorld db "Hello World!", 0
.code
start:
invoke MessageBox, NULL, addr HelloWorld, addr HelloWorld, MB_OK
invoke ExitProcess, 0
end start
现在,再打开命令行并转到"hellow.asm"所在目录。输入"\masm32\bin\ml /c /Zd /coff hellow.asm"回车,接着输入"\masm32\bin\Link /SUBSYSTEM:WINDOWS hellow.obj"并回车。注意,subsystem是WINDOWS不再是CONSOLE。这个程序弹出一个显示"Hello World!"的信息框。
与控制台版相比,窗体版本的代码只有3行是不同的。其中有两行把masm32包含文件和库文件更换为user32包含文件和库文件,这是因为我们现在是使用MessageBox函数,而不是使用StdOut了。第3个不同的行是用MessageBox函数代替了StdOut函数。不同之处就这么多而已!
ADDR 与 OFFSET
在我们“Hello World!”程序例子中,我们使用了'addr' 来获取字符串"Hello World!"的地址。还有另外一个类似的指令'offset',虽然两者的目的都是在程序执行中获取变是变量的地址。它们主要的区别是'offset' 只能获取全局变量的地址,然而addr能获取全局变以及局部变量的地址。然而我们不讨论局部变量,所以不用担心这种区别。但是我们还是要记住这种区别的。
Ⅲ 汇编基础
cpu寄存器
现在我们已经能够编写并运行一个简单的程序了。让我们转到本教程的核心内容-汇编基本语法吧。你要写出自己的汇编程序,这些基本的知识是要掌握的。 32位通用寄存器有8个。它们其中前面四个也就是eax,ebx,ecx,edx,也能用它们16位或8位的名字形式进行存取。比如,ax存取eax的低16位,al存取低8位,还有ah存取的是9到16位。其余的寄存器也能以类似的方式进行存取。就如大家想象的那样,这些通用寄存器虽然大多有专用的用途,但它们有通用的地方。
地址 | 名称 | 描述 |
EAX* | 累加寄存器 | 进行计算操作和保存数据结果 |
EBX | 基址寄存器 | 指向数据寄存器中的数据 |
ECX* | 计数寄存器 | 字符串以及循环的计数 |
|