引言
汇编的相关基础知识我们了解的差不多了,现在我们可以尝试写第一个汇编程序。
源程序
先来看一个例子:
assume cs:codesg
codesg segment
start:
mov ax,0123h
mov bx,0456h
add ax,bx
add ax,bx
mov ax,4c00h
int 21h
codesg ends
end start
下面我们来“拆”一下这个实例程序
1.伪指令
在汇编语言中有两种指令:汇编指令、伪指令。
这两个指令我们这钱已经介绍过了,汇编指令有对应的机器指令,伪指令没有对应的机器指令,由编译器负责处理。 这段源程序中有三种伪指令:
(1)声明一个段
xxx segment
…
…
xxxxx ends
segment与ends是成对使用的,用来申明一个段。一个段必须有一个段名来标识,格式如下:
段名 segment
…
…
段名 ends
(2)end
end是一个汇编程序的结束标记,当编译器碰到end时,就停止对源程序的编译。一定要区别end与ends.(3)assume
这条伪指令的含义是“假设”。它假设某一段寄存器与源程序中的用segment ends声明的一个段相关联。源程序中的“程序”:是指源程序中能够被编译成机器指令的代码。
2.标号:
除了汇编指令与伪指令外,还有一些标号,例如示例程序中的codesg。
程序的结构
我们编写的程序要编译器能够识别并编译,那么程序就必须有自己的结构,下面说说程序的结构。现在我们编程计算2^3.
(1)每个程序都是由一个个段组成的,所以首先定义一个段,名称为codesg:
codesg segment
…
…
codesg ends
(2)向段中添加汇编指令,来实现2^3
codesg segment
mov ax,2
add ax,ax
add ax,ax
codesg ends
(3)指出我们的源程序在哪里结束
codesg segment
mov ax,2
add ax,ax
add ax,ax
codesg ends
end
(4)codesg被当做代码段使用,所以需要将它与代码段寄存器联系起来:
assume cs:codesg
codesg segment
mov ax,2
add ax,ax
add ax,ax
codesg ends
end
现在一个小程序正式写完了,是不是很轻松呢。
程序返回
现在源程序倒是写完了,但是我们的最终目标是执行这个程序啊,那么要如何进行了,这就得再说一说在DOS基础上源程序是怎么被cpu执行的了。
一个程序p2在可执行文件中,则必须有一个正在运行的程序p1,将p2从可执行文件家载入内存后,将cpu的控制权交给p2,p2才能得以运行,p2开始运行后,p1暂停运行。p2运行完毕后,cpu的控制权交还给p1,最后这个交还动作就是所谓的程序返回。
关于计算机程序是如何运行的(详细)请到这里:计算机程序到底是如何运行的
但是cpu自己是不会主动把一个控制权从p2还给p1的,这就需要我们程序员自己来做,怎么做呢?
看一下我们的示例程序中比起我们刚刚自己写的那个程序多了两行代码:
mov ax,4c00h
int 21h
其实这两行代码就起到了一个程序返回的作用。
我们现在已经解除了几个和结束相关的指令内容了,做一个对比:
运行我们的程序
下面我们就在dosbox环境下运行我们刚刚写的程序。要运行首先得把我们的源程序转化为可执行文件,两个步骤:编译、连接。
我将我们刚刚写的程序保存为two.asm
assume cs:codesg
codesg segment
mov ax,2
add ax,ax
add ax,ax
mov ax,4c00h
int 21h
codesg ends
end
打开dosbox
(1)编译
输入指令 masm two.asm,然后按提示操作
编译成功,生成two.obj文件
(2)连接
输入命令 link two.obj
连接成功,(忽略那个warning,因为现在还没有用到stack segment),生成two.exe文件
(3)执行exe文件
执行成功!虽然屏幕上看不到任何东西,但是的确成功了,因为我们没有让cpu将结果显示在屏幕上,那么怎么查看结果呢?还记得debug吗,我们可以用它来查看寄存器中的内容。
(4)debug查看ax
输入命令 dubug two.exe,回车后再输入t,t表示单步执行我们的程序,这样我们就可以很清晰的看到我们的程序作了什么。
可见现在已经执行了mov ax,2这一操作了,所以ax=2,下一步操作是add ax,ax
继续单步执行
ax内容为4,下一步是add ax,ax
继续单步执行
ax内容为8,下一步为mov ax ,4c00h
到目前为止已经实现了2^3的运算。也不必往下看了。
了解内容:
每天进步一点点