未分类

WINDOWS平台下的X86汇编

本文采用DOS下的masm汇编器编写汇编语言,本文介绍的汇编代码为16位汇编,寄存器都为ax,al之类的16位寄存器,没有eax这样的32位寄存器。

进入一台安装好masm的DOS虚拟机,因为要运行16位汇编,所以要用DOS操作系统。进入后输入pwb打开编译界面,开始编写汇编。

汇编有byte,word,dword这样的类型区分,区分的方法为数据的位数,word为8为,dword为16位(double word),byte好像位4位,如果用16进制数表示的话,word就占两位数。

首先看一个问题。


试编写8086汇编程序,统计由主存40000H开始的16k哥单元中所存放的的字符“A”的个数,并将结果放在DX中。

示例:(不可直接运行)
start:
    mov dx,4000h
    mov ds, dx
    mov cx, 16*1024
    mov si, 0
    mov dx, 0
find:
    mov al, [si]
    cmp al, 'A'
    jnz next
    inc dx
next:
    inc si
    loop find
    ......

分析:

首先,汇编代码如果没有loop,jmp之类的跳转指令的话,默认是从上往下执行的,也就是说start段执行完之后,立即接着执行find段的代码。

因为要从40000h开始,这个数显然16位寄存器存不下,因为有20位,所以这里使用了寄存器间接寻址的方式,需要使用ds寄存器,但是这个ds寄存器默认是无法直接放入数据的,需要通过其他寄存器传参数进去。同时,ds寄存器初始化的时候输入的数据为段起始地址的高16位,即4000h。同时需要将指针寄存器(si,di,或bx等)初始化为0。这里使用了si指针寄存器,ds寄存器的地址加上si的值即为我们需要访问的内存的地址。代码中的 mov al, [si]即为将[si]内存地址上的值传入al,如果是mov al, si就是将si的值传入al了。

这里的cmp和jnz表示不相等即跳转,跳转到next,具体的实现为,cmp 对象1,对象2,计算对象1-对象2,结果不保存,根据运算的结果修改对应的标志寄存器,ZF,PF,SF,CF,OF,然后jnz根据标志寄存器的结果判断是否要进行跳转。(具体怎么修改标志寄存器我忘了)

inc dx为将dx存的数加一。

loop find这里应用到了cx寄存器中的值,因为开始cx寄存器中的值已经初始化为16*1024了,这里是后面那个数为立即数,loop的时候每次先将cx中的值减一,当cx为0的时候loop终止。所以当一开始就是0的时候循环次数的最多的

find段开始的两行代码使用了al寄存器,这就是一个8位的寄存器,用来存放byte,就一个字。同时这两行代码可以转换成 CMP BYTE PTR [SI], ‘A’ 这里因为要比较使用了PTR关键字,用来将[si]寄存器中的值转换成byte的。

 

接下来我们来看第二个问题。


在DATA为首地址的主存区域中存放100个无符号的8位数,试编写程序找出其中最大的数,并将其存放在KVFF存储单元中

(可直接运行)
.model small
.stack 4096

.data
    DATA BYTE 100 DUP(?)
    KVFF BYTE 0
code segment
start:
    mov ax, @data
    mov ds, ax
    mov bl, 0
    mov si, 0
    mov cx, 100
L2:
    cmp DATA[si], bl
    JBE L3
    inc si
    loop L2
    imp L4
L3:
    mov bl, DATA[si]
    inc si
    loop L2
L4:
    mov KVFF, bl
    mov ah, 4ch
    int 21h
code ends
end start

开头的.model small为小段存储的存储方式,这个不要关心太多,反正这么写就对了。

.stack 4096初始化堆栈大小。写4096基本就够用了。

.data为数据段,其实也可以直接将这段代码写进code段里面,个人习惯问题。首先将DATA初始化为一个100个BYTE的数组,每个数据用?表示随机,100表示数量,后面的DUP表示循环赋值。将KVFF初始化为一个BYTE类型的0.

在code段中,code segment开始,code ends结束。首先将data段中的数据传进来。因为前面是用 . 开头的,所以要用@引用。

在L4段中,后面的mov ah, 4ch以及int 21h用来结束程序。相当于C语言中的return。

 

接下来看第三个问题


试编写程序,给从内存40000h到4BFFFh的每个单元中均写入55h,并逐个单元比较。若写入的与读出的完全一致,则将AL置7Eh,若有错则将AL置81h。

.model small
.stack 4096
data segment
    base WORD 4000h
data ends

code segment
start:
    assume ds:data, cs:code
    mov ax, data
    mov ds, ax
   
    mov dx, base
    mov ds, dx
    mov si, 0
    mov cs, 0C000h
    mov al, 55h
L1:
    mov [si], al
    inc si
    loop L1
   
    mov si, 0
    mov cx, 0C000h
L2:
    cmp [si], al
    jnz L3
    inc si
    mov al, 7Eh
    loop L2
    jmp L4
L3:
    mov al, 81h
L4:
    mov ah, 4ch
    int 21h
code ends
end start

这里的assume就是声名哪些试数据段,那些是代码段。

 L2中的[si]就等价于ds[si],但是也可以写成mov dx, SEG base mov ds, dx mov si, OFFSET base

最后来一段网上抄的没测过的输出“hello word123456789”,原文链接https://blog.csdn.net/springcsc1982/article/details/54987484


assume cs:code,ds:data
data segment
   str1 db 'hello world123456789$'
data ends

code segment
start:
   mov ax,data
   mov ds,ax
   
   mov dx,offset str1

   mov ah,09h
   int 21h

   mov ah,4ch
   int 21h

code ends
end start

 

Leave a Reply

邮箱地址不会被公开。 必填项已用*标注