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