中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » A introduction to x86 assembly(二)
作者:
标题: A introduction to x86 assembly(二) 上一主题 | 下一主题
fdsiuha
高级用户




积分 587
发帖 302
注册 2005-7-25
状态 离线
『楼 主』:  A introduction to x86 assembly(二)

以下是A introduction to x86 assembly的第二部分

--------------------------------------------------------------------------------------------------------

语法:
        SUB 操作数1,操作数2

从操作数1中减去操作数2. 当然操作数1不能是立即数,但是操作数2可以是。

MUL        两个无符号的整数相乘 (总是正的)
IMUL        两个有符号的整数相乘 (可正可负)

语法:
        MUL 寄存器或变量
        IMUL 寄存器或变量

与寄存器AL或AX中的数字相乘,至于选择哪个,是由操作数的大小决定的。
计算结果放入AX。如果计算结果大于 16 位的话,计算结果将放入DX:AX中
(高16位在DX中,低16位在AX中)。

在386、486或Pentium中可以使用EAX寄存器,其计算结果也将放入到EDX:EAX中。

DIV        两个无符号的整数相除(总是正的)
IDIV         两个无符号的整数相除(可正可负)

语法:
        DIV 寄存器或变量
        IDIV 寄存器或变量

其工作方式与MUL和IMUL是一样的。AX中的数被给定的寄存器或变量除。
计算结果储存分在两个部分中。AL中的是商而余数放在AH里。如操作数是
16位的寄存器,那么被除的数放在DX:AX中的数,计算结果储存在AX中,余数在DX中。


至于存取我们所要想显示的信息的地址则有点麻烦。这程序将占据3行,并且不是那么好记住。

        mov dx,OFFSET MyMessage                                               
        mov ax,SEG MyMessage                                               
        mov ds,ax               

也可以用下面仅仅一行程序来取代它。而且这样会使你的程序易读易记。
但是注意,只有要读取数据在同一个段里的时候它才能正常工作。比如说小内存模式。

        lea dx,MyMessage
或        mov dx,OFFSET MyMessage
使用lea不仅会执行慢些,而且增加编译后代码的长度。

LEA 的意思是读有效地址(Load Effective Address).

语法:
LEA destination(目的),source(源)

Desination 可以为16位的寄存器,内存操作数(内存中的数据位,译注:内存地址所对应的标号)。
这将把源数据的地址偏移量送到目的寄存器中。

键盘输入:

我们将使用16h号中断,用其00h号功能来读键盘操作。它将从键盘缓存中取出一个键。
如果键盘缓存是空的, 它将一直等待到有一个键被送到这里。它会返回键的扫描码(SCAN
code)到AH中,并翻译出该键的ASCII码到AL中。

   MOV ah,00h                ;00h号功能
   INT 16h                ;16h中断

好了,我们接下来所考虑的问题就是ah现在里面的ASCII码是什么。

打印(译注:显示到屏幕)一个字符:

现在问题的关键是,我们已经把一个键放在ah中了。我们如何来显示它?我们不能够使用
9h功能,因为这样的话,我们把它转化为一个以美圆符结尾的字符串。我们现在这样做:

;在调用16h中断的00h功能后
        MOV dl,al       ;将al内容(ascii code)放入dl中
        MOV ah,02h      ;21h中断的02h号功能
        INT 21h         ;调用21h中断

如果你想保存一个值的话,你可以先使用PUSH,以后再用POP弹出来。


流程控制:
首先,下面是最基本的命令:
        JMP label
与basic语言里面的GOTO语句很像吧?

                JMP ALabel
     .
        .
        ALabel:
             ;你要编写的代码

如果我们想比较两个数的大小该怎么办呢?我们从用户中得到了一个键,我们将对它
进行处理。比如当它与某个值相等,那就显示另外一个信息。我们怎样达到这个目的呢?
其实非常简单。我们使用条件跳转指令,以下是列表:

条件跳转指令:

JA
如果第一个值大于第二个值,就跳转

JAE
与上面的那条相同,只是当两值相同时,也要跳转

JB
如果第一个值小于第二个值,就跳转

JBE
与上面的那条相同,只是当两值相同时,也要跳转

JNA
第一个值不大于第二个值则跳转  (同JBE)

JNAE
第一个值不大于等于第二个值则跳转 (同JB)

JNB
第一个值不小于第二个值则跳转  (同JAE)

JNBE
第一个值不小于等于第二个值则跳转 (same as JA)

JZ
两数相同就跳转

JE
与JZ相同,只是叫法不一样罢了

JNZ
两数不同就跳转

JNE
同上



[注意: 其实有更多的跳转指令,只不过这是最常用的. 如果你想得到完整的列表就去弄本
好一点的汇编语言教材]

它们很容易使用。

语法:
        CMP 包含一个数的寄存器,一个值
    跳转指令 目的地址   

这是一个例子:
      cmp al,'Y'      ;把al中的值与Y相比较
      je ItsYES       ;如果相等就跳转到ItsYES

下面的程序是如何使用控制命令和输入输出命令的例子.

.MODEL  SMALL
.STACK                                         ;定义一个栈
.CODE
Start:                                        ;就在这里开始吧
         
      lea dx,StartUpMessage          ;显示一个信息
      mov ah,9                ;使用09h号功能
      int 21h                 ;21h中断
      lea dx,Instructions     ;显示一个信息
      mov ah,9                ;使用09h号功能
      int 21h                 ;21h中断
      
      mov ah,00h              ;00h号功能
      int 16h                 ;16h中断将从用户那里得到一个字符     
      mov bl,al               ;保存bl   
      mov dl,al               ;将按键的ASCII码放入到dl中
     
      mov ah,02h              ;02h号功能
      int 21h                 ;21h中断显示一个字符到屏幕
      cmp bl,'Y'              ;al=Y?
      je Thanks               ;确实相等就跳到Thanks继续执行
      cmp bl,'y'              ;al=y?
      je Thanks               ;确实相等就跳到Thanks继续执行
      jmp TheEnd
Thanks:
      lea dx,ThanksMsg        ;显示信息
      mov ah,9                ;使用9号功能
      int 21h                 ;21h中断
TheEnd:
      lea dx,GoodBye          ;显示一个结束信息
      mov ah,9                ;使用9号功能
      int 21h                 ;21h中断
      mov AX,4C00h            ;结束程序并返回DOS
      INT 21h                 ;21h号中断的4CH功能

.DATA                           
;0Dh,0Ah 是在字符串开始的地方加入的一个入口信息

StartUpMessage DB "A Simple Input Program$"     
Instructions  DB 0Dh,0Ah,"Just press a Y to continue...$?                 
ThanksMsg      DB 0Dh,0Ah,"Thanks for pressing Y!$"   
GoodBye        DB 0Dh,0Ah,"Have a nice day!$"

        END

过程:

汇编语言、C和Pascal都可以使用过程。对于一系列需要重复执行的指令来说是非常重要的。

以下是过程的定义方法:

PROC AProcedure
    .
    .          ;完成一些工作的代码      
    .
    RET                ;这东西不出现在过程的结尾的话,就会当机
ENDP AProcedure

你可以指定如何来调用一个过程,只需要在过程名字后面加上一个FAR或者一个NEAR就行了
否则它将使用你正在使用的内存模式。目前在你不是很有经验的情况下还是不要随便这样做。
我经常使用NEAR,因为编译器不能够区别近的调用和远的调用。这里的意思是说,如果是
远的跳转的话,那么编译器将会发出警告,这样的话你就可以替换掉它。

这是一个使用过程的程序。

;一个简单的使用过程的程序,在屏幕上显示一条信息
;(使用tlink的/t选项)。它会在屏幕上显示Hello There!。

.MODEL  TINY
.CODE
ORG     100h

MAIN    PROC
           JMP Start                   ;跳过字符串定义
HI      DB "Hello There!$" ;define a message
Start:                                  ;在这里开始
        Call Display_Hi    ;调用过程
        MOV AX,4C00h       ;终止程序并返回DOS
        INT 21h            ;21h号中断的4CH功能

Display_Hi PROC            ;定义一个过程的开始
        lea dx,HI          ;把信息的地址放入到DX里
        mov ah,9           ;9号功能
        int 21h            ;21h中断
        RET                ;不要忘了这个东东!
Display_Hi ENDP            ;定义过程的结尾

Main    ENDP
        END MAIN

[ Last edited by fdsiuha on 2005-10-29 at 21:38 ]



欢迎造访DOS的小屋!
http://risky.ik8.com
2005-10-29 21:20
查看资料  访问主页  发短消息 网志   编辑帖子  回复  引用回复
Michael
钻石会员





积分 10046
发帖 3039
注册 2002-11-11
状态 离线
『第 2 楼』:  

我还以为是英文的,进来一看不是。



简单就是美
2005-10-31 09:19
查看资料  发短消息 网志   编辑帖子  回复  引用回复
fdsiuha
高级用户




积分 587
发帖 302
注册 2005-7-25
状态 离线
『第 3 楼』:  

这是我翻译的,要原文也有...



欢迎造访DOS的小屋!
http://risky.ik8.com
2005-10-31 09:53
查看资料  访问主页  发短消息 网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: