汇编实验最终版

汇编实验

关于debug

-t逐步调试,注意各个寄存器的值即可

实验1

编写一个累计加法,从 1 加到 5,将结果保存至 AX 中。

assume cs:cseg,ds:data
data segment
    infor1 db 'welcome to work1!'
data ends
cseg segment
start:mov dx,offset infor1;offsert返回的是infor1的偏移地址
      mov ax,1234h
      mov ds,ax
	  mov bx,0005h
	  
	  mov ax,0
	  mov dx,1
	  mov cx,5

    s:add ax,dx
	  inc dx;(dx)++
	  loop s
	  
	  mov ds:[bx],ax;程序返回
      mov ax,4c00H;程序返回
      INT 21H
cseg ends

end start

实验2

编写一个累计减法,被减数是 10011000B,减数是 01000000B,连续减 5 次, 观察 FLAGS 的变化

assume cs:cseg,ds:data
data segment
    db 'welcome to masm!'
data ends
cseg segment
start:mov ax,1234h
      mov ds,ax
	  mov bx,0005h
	  
	  mov ax,10011000B
	  mov dx,01000000B
	  mov cx,5

    s:sub ax,dx
	  loop s
	  
	  mov ds:[bx],ax
	  
      mov ax,4c00H
      INT 21H
cseg ends

end start

98-40-…减到0时从FFFF再开始减

标识寄存器flags:

有符号溢出标志位OF(Over flow flag) OV(1) NV(0)
方向标志位DF(Direction flag) DN(1) UP(0)
中断标志位IF(Interrupt flag) EI(1) DI(0)
符号标志位SF(Sign flag) NG(1) PL(0)
零标志位ZF(Zero flag) ZR(1) NZ(0)
辅助进位标志位AF(Auxiliary carry flag) AC(1) NA(0)
奇偶标志位PF(Parity flag) PE(1) PO(0)
无符号进位标志位CF(Carry flag) CY(1) NC(0)

在这里插入图片描述

实验3

编写一个 16 位的乘法,被乘数是 100H,乘数是 100H,观察 Flags 的变化

assume cs:cseg,ds:data
data segment
    db 'welcome to masm!'
data ends
cseg segment
start:mov ax,1234h
      mov ds,ax
	  mov bx,0005h
	  
	  mov ax,0
	  mov dx,100H
	  mov cx,100H

    s:add ax,dx
	  loop s

	  
      mov ax,4c00H
      INT 21H
cseg ends

end start

编写一个 32 位的乘法,被乘数是 0F0FH,乘数是 FF00H,观察 Flags 的变化

assume cs:ccode, ds:ddata
ddata segment
      x1 dw 0F0FH		;被乘数低四位
      x2 dw 0000H		;被乘数高四位
      y1 dw 0FF00H		;乘数低四位
      y2 dw 0000H		;乘数高四位
      xy dw 4 dup (?)	;dup重复定义指令,dw为定义的类型,开辟出4个字的单元空间
ddata ends
ccode segment
start:mov ax,ddata
      mov ds,ax

      mov ax,x1
      mov dx,y1
      mul dx
      mov [xy],ax
      mov [xy+2],dx     ;被乘数低位4字符x1和乘数低位4字符y1相乘结果低位存入xy,高位存入xy+2

      mov ax,x2
      mov dx,y1
      mul dx
      add [xy+2],ax
      adc [xy+4],dx      ; 被乘数高位4字符x2和乘数低位4字符y1相乘结果低位存入xy+2,高位存入xy+4

      mov ax,x1
      mov dx,y2
      mul dx
      add [xy+2],ax
      adc [xy+4],dx
      adc [xy+6],0       ; 被乘数低位4个字符x1和乘数高位4个字符y2相乘结果低位存入xy+2,高位存入xy+4

      mov ax,x2
      mov dx,y2
      mul dx
      add [xy+4],ax
      adc [xy+6],dx      ; 被乘数高位4个字符x2和乘数高位4个字符y2相乘结果低位存入xy+4,高位存入xy+6

      mov ah,4ch
      int 21h

ccode ends
end start

在这里插入图片描述
在这里插入图片描述

实验4

编写一个 16 位的除法,被除数是 100H,除数是 100H,观察 Flags 的变化

assume cs:cseg,ds:data
data segment
    db 'welcome to masm!'
data ends
cseg segment
start:mov ax,1234h
      mov ds,ax
	  mov bx,0005h
	  
	  mov ax,100H
	  mov bx,100H
      div bx  
	  
      mov ax,4c00H
      INT 21H
cseg ends

end start

编写一个 32 位的除法,被除数是 0F0FH,除数是 00FFH,观察 Flags 的变化

借鉴TeaMakCoder思想:https://blog.csdn.net/Fgoodboy/article/details/109067736

这里需要用到一个公式:

X/N = int(H/N)*65536 + [rem(H/N)*65536+L]/N -----------------------公式①
X:被除数
N:除数
H:被除数X的高16位
L:被除数X的低16位
int()取商
rem()取余数

给出示例参数:

(ax)寄存器储存被除数的低16位 mov ax,4240h
(dx)寄存器储存被除数的高16位 mov dx,000fh
(cx)寄存器储存16位的除数 mov cx,000ah
除法结果的高16位储存在(dx)中,低16位储存在(ax)中,余数储存在(cx)中
仔

仔细观察公式①的第一项:

int(H/N)*65536

int(H/N):被除数的高16位/除数,这里将H拓展为一个32位的数(0000xxxxh),由于其高16位全为0,所以H/N的商一定不会溢出(超过16位)。

那乘以65536应该怎么做呢?我们只需要记得将H/N的商放到一个代表高16位的寄存器中就可以了,并不需要真的乘65536(事实上*10000h也无法简单地用16位乘法实现)。

再看公式②的第二项:

[rem(H/N)*65536+L]/N

rem(H/N)已经在第一项除法中得到了,假设 X = rem(H/N),接下来实现(X+L)/N,显然也是一个32位数/16位数的除法。但这里存在一个问题:如何保证除法的商不会溢出呢?

在这里简单的证明一下:

因为 X 是 H/N 的余数,所以 X<=N-1 (X不可能大于N),L是被除数的低16位,不妨令 X=N-1,L=FFFFh。只需证明

[(N-1)|FFFFh]/N<10000h

(((N-1)|FFFFh)以N-1为高16位,以FFFF为低16位。比如N-1 = FFFE,则分子为FFFEFFFFh)。

原式=[(N-1)*65536 + 65535]/N=65536 - 1/N < 10000h

assume ds:datasg,ss:stacksg,cs:codesg
datasg segment

datasg ends
stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends
codesg segment
start:mov ax,stacksg
		mov ss,ax
		mov sp,16
		mov ax,0000h
		mov dx,0F0Fh
		mov cx,0FF00h
		call divdw
		
		mov ax,4c00h
		int 21h
		;参考公式X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N
		;可以把该32位/16位的除法视作2个伪16除法,高位(dx)中存的是0
		;首先低四位除以除数,得到16位的商,这个商就是高16位结果(为什么?)
		;上一步的余数左移16位后加上低16位构成32位数
		;尝试证明第二步除法不会溢出:
		;rem<=N-1,L<=0FFFFh
		;res = (N-1)|0FFFFh/N = [65535+(N-1)*65536]/N = 65536-1/N
		;1<=N<=FFFFh,所以res<=FFFF(极端情况下也不会溢出)
divdw:push bx;防止寄存器冲突覆盖原有的值
		push ax;低16位进栈
		mov ax,dx;32位/16位
		mov dx,0
		div cx;int(H/N)*65536,商AX,余数DX,商AX就是最终结果的高16位
		mov bx,ax;bx保存高16位商
		pop ax;低16位送入ax中
		push bx
		div cx;[rem(H/N)*65536+L]/N,低16位商AX不用动,余数DX
		mov cx,dx;cx中保存的是余数
		pop dx;dx中是高16位商
		pop bx;恢复寄存器
		ret
		
codesg ends
end start

实验5

编写一个累计加法,被加数是 0FH,加数是 01H,观察 Flags 的变化,被加数是 0FFH,加数是 01H,观察 Flags 的变化,被加数是 0FFFH,加数是 01H, 观察 Flags 的变化,被加数是 FFFFH,加数是 01H,观察 Flags 的变化,被 加数是 FFFFFFFFH 加数是 01H,观察 Flags 的变化

assume cs:cseg,ds:data
data segment
    infor1 db 'welcome to work1!'
data ends
cseg segment
start:mov dx,offset infor1
      mov ax,1234h
      mov ds,ax
	  mov bx,0005h
	  
	  mov ax,0FH
	  mov dx,01H
	  add ax,dx	  
	  mov ds:[bx],ax
	  mov ax,4c01H
	  
	  mov ax,0FFH
	  mov dx,01H
	  add ax,dx	  
	  mov ds:[bx],ax
	  mov ax,4c02H
	  
	  mov ax,0FFFH
	  mov dx,01H
	  add ax,dx	  
	  mov ds:[bx],ax
	  mov ax,4c03H
	  
	  mov ax,0FFFFH
	  mov dx,01H
	  add ax,dx	  
	  mov ds:[bx],ax
	  mov ax,4c04H
	  
	  mov ax,0FFFFH
	  mov bx,0FFFFH
      add bx,0001H
	  adc ax,0000H		;带进位的加法,将CF一起加进去
	  mov ax,4c05H
	  

      mov ax,4c00H
      INT 21H
cseg ends

end start

实验6

编写一个移位运算,将 8F1DH 存至 AX,然后用指令右移 1 位然后左移 1 位, 显示结果并观察 Flags 的变化。将 8F1DH 存至 AX 中,然后带 CF 位左移 5 位,并右移 7 位,观察 Flags 的变化,并给出结果

assume cs:cseg,ds:data
data segment
    db 'welcome to masm!'
data ends
cseg segment
start:mov ax,1234h
      mov ds,ax
	  mov bx,0005h
	  
	  mov ax,8F1DH
	  sar ax,1			;算数右移
	  sal ax,1			;算术左移
	  mov ax,4c01H
	
      mov ax,8F1DH
	  mov cx,5
	  
	loop1:
      rol ax,1			;循环左移
	  loop loop1

	  mov cx,7

    loop2:
	  sar ax,1
	  loop loop2
	  	  
	  mov ax,4c02H
      mov ax,4c00H
      INT 21H
cseg ends

end start

实验7

将 71D2H 存至 AX 中,5DF1H 存至 CX 中,DST 为 AX,REG 为 AX,实现双精度右移 2 次,交换 DST 与 REG,然后左移 4 次,分别查看结果

这里本来用的是masm来写,发现masm识别不了shrd和shld

assume cs:cseg,ds:data
data segment
    db 'welcome to masm!'
data ends
cseg segment
start:mov ax,1234h
      mov ds,ax
	  mov bx,0005h
	  
	  mov ax,71D2H
	  mov bx,5DF1H
	  mov cx,2
	  
l1:	  sar bx,1
	  sar ax,cl
	  loop l1
	  
	  mov ax,5DF1H
	  mov bx,71D2H 
	  mov cx,4
l2:   sar bx,1
	  sar ax,cl
	  loop l2
     
     
      mov ax,4c00H
      INT 21H
cseg ends

end start

实验8

实现压缩BCD码的加减法,用压缩BCD码实现(21+71),(12+49),(65+82), (46-33),(74-58),,(43-54)的十进制加减法。然后又用非压缩 BCD 实现 上述 6 个式子。

assume cs:cseg,ds:data
data segment
    infor1 db 'welcome to work1!'
data ends
cseg segment
start:mov dx,offset infor1
      mov ax,1234h
      mov ds,ax
	  mov bx,0005h

;压缩BCD码
;-------------------
;21+71
    mov al,21h
    mov bl,71h
    add al,bl
    daa				;压缩BCD码的调整指令
;12+49
    mov al,12h
    mov bl,49h
    add al,bl
    daa
;65+82
    mov al,65h
    mov bl,82h
    add al,bl
    daa
;46-33
    mov al,46h
    mov bl,33h
    sub al,bl
    das
;74-58
    mov al,74h
    mov bl,58h
    sub al,bl
    das
;43-54
    mov al,43h
    mov bl,54h
    sub al,bl
    das
;非压缩BCD码
;-------------------
;21+71
    mov ax,0201H
    mov bx,0701H
    add ax,bx
    aaa				;非压缩BCD码调节指令
    				;调整方法与AAA指令类似,不同的是DAA指令要分别考虑AL的高4位和低4位。
    				;如果AL的低4位大于9或AF=1,则AL的内容加06H,并将AF置1;然后如果AL的高4位大于9或CF=1,则AL的内容加60H,且将CF置1。如果两个都不满足,则将AF,CF清零。
;12+49
    mov ax,0102H
    mov bx,0409H
    add ax,bx
    aaa				;AAA为非压缩BCD码调整,即如果al低四位大于9,就将al加6,ah加一,al高四位清零,cf、af置1。
;65+82
    mov ax,0605h
    mov bx,0802h
    add ax,bx
    aaa
;46-33
    mov ax,0406h
    mov bx,0303h
    sub ax,bx
    aas
;74-58
    mov ax,0704h
    mov bx,0508h
    sub ax,bx
    aas
;43-54
    mov ax,0403h
    mov bx,0504h
    sub ax,bx
    aas



    mov ax,4c00H
    INT 21H
cseg ends

end start

在这里插入图片描述

实验9

实现 KMP 算法,输入两个字符串(可以直接保存在内存中),实现快速匹配

DATAS SEGMENT
    ;此处输入数据段代码
    mess1 DB 'Enter keyword:','$'
    mess2 DB 'Enter Sentence:','$'
    mess3 DB 'Match at location:','$'
    mess4 DB 'NOT MATCH.',13,10,'$'
    mess5 DB 'H of the sentence',13,10,'$'
    change DB 13,10,'$'
    stoknin1 label byte			;LABEL可以使同一个变量具有不同的类型属性,其中变量的数据类型可以是BYTE,WORD,DWORD
    max1 db 10 	;关键字大小
    act1 db ?	;记录
    stokn1 db 10 dup(?)
    stoknin2 label byte
    max2 db 50  ;字符串大小
    act2 db ?	;记录
    stokn2 db 50 dup(?) 
    
DATAS ENDS

STACKS SEGMENT

STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
    
START:
    MOV AX,DATAS
    MOV DS,AX
    
    LEA DX,mess1
    MOV ah,09
    INT 21h			;输出Enter keyword
    LEA DX,stoknin1	;lea,取有效地址
    MOV ah,0ah		;用21号中段的0ah号功能获取关键字
    INT 21h
   
    cmp act1,0
    je exit			;如果为空直接退出程序
a10: 
    ;输入Sentence并判断
    LEA DX,change
    MOV ah,09
    INT 21h			;输出回程,换行
    LEA DX,mess2 
    MOV ah,09
    INT 21h
    				;输出Enter Sentence:
    LEA DX,stoknin2
    MOV ah,0ah
    INT 21h
   		 			;用21号中段的0ah号功能获取句子
    MOV AL,act1
    CBW
    MOV CX,AX
    				;保存关键字长度到cx
    PUSH CX
    				;cx入栈
    MOV AL,act2
    cmp AL,0
    je a50
    				;保存句子长度到al,若句子为空则跳转显示not match
    SUB AL,act1
    js a50
    				;若句子长度小于关键字长度,则跳转显示not match
    INC AL
    CBW
    LEA BX,stokn2
    				;将句子的首地址放进BX
    MOV DI,0
    MOV SI,0 
a20:
    				;比较,内循环 
    MOV AH,[BX+DI]
    CMP AH,stokn1[SI]
    				;遇见字符不相等就跳转到a30
    jne a30
    INC DI
    INC SI
    DEC CX
    				;没遇到一个相等的字符,cx-1,若cx不为0则比较下一个字符,当cx为0是说明关键字比较完
    CMP CX,0
    je a40
    jmp a20
a30:

	;外循环,BX+1,清空si,di继续内循环比较
	INC BX
	DEC AL
	cmp AL,0
	je a50
	MOV DI,0
	MOV SI,0
	POP CX
	push CX
	jmp a20
a40:

	;match,将bx减去句子的首地址加一得到关键字所在位置,调用二进制转十六进制子函数将位置输出
	SUB BX,offset stokn2
	INC BX
	LEA DX,change
	MOV ah,09
	INT 21h
	LEA DX,mess3
	MOV ah,09
	INT 21h
	CALL btoh
	LEA DX,mess5
	MOV ah,09
	INT 21h
	jmp a10
	
	;二进制转换十六进制
	btoh PROC NEAR
	MOV CH,4
	rotate: MOV CL,4
	ROL BX,CL
	MOV AL,BL
	and AL,0fh
	add AL,30h
	cmp al,3ah
	jl printit
	add al,7h
	printit:
	MOV dl,al
	MOV ah,2
	int 21h
	dec ch
	jnz rotate
	ret
btoh endp
a50: 

	;显示not match
	LEA DX,change
	MOV ah,09
	INT 21h
	LEA DX,mess4
	
	MOV ah,09
	INT 21h
	jmp a10
exit:
	ret
CODES ENDS
    END START

在这里插入图片描述

首先需要有输入限制要求,即输入的关键字长度不能大于句子的长度。然后是比较句子中的字符和关键字,利用cld依次将si、di增1,repz cmpsb比较si、di指向的字符,若三次比较均成功,则跳转至match(表示匹配成功),在match中实现将句子中匹配成功的首地址存放在bx中。否则继续下面的执行,恢复si指针指向关键字首地址,di指向句子的匹配失败的首地址的下一个地址,然后继续循环compare(继续寻找匹配),若最后失败则执行到wrong。

实验10

斐波纳契数列:1,1,2,3,5,8,13。通常可以使用递归函数实现,现用汇编实现该过程

assume cs:codesg,ds:datasg1

datasg1 segment
    num dw 8 dup(0)
    ;42417671442657
    extra dw 8 dup(0)
    ans db 32 dup(0)
datasg1 ends

datasg2 segment
    dw 1600 dup(0)
    string db 'please input an int from 1 to 150:$'
datasg2 ends



codesg segment
start:
    mov ax,datasg2
    mov ds,ax
    mov si,0
    mov di,16

    mov word ptr [si],0
    mov word ptr [di],1

    call fib

    mov dx,offset string 
    mov ah,9h
    int 21h
    


    mov bx,10
    mov cx,0
l1: 
    mov ah,01h  ;中断调用,单字符输入
    int 21h     ;输入符号的ASCⅡ代码在AL寄存器中

    cmp al,0dh 
    jz over

    sub al,30h 
    add al,cl
    mov ah,0
    mul bx
    mov cx,ax

    jmp l1

over:
    mov ax,cx
    div bx
    mov cx,16
    mul cx
    mov si,ax

    mov ax,datasg1
    mov es,ax

    
    mov di,0

    mov cx,16
    rep movsb

    call show_answer




    mov ax,4c00h
    int 21h 

fib:
    mov cx,150
    s1:
        call add_128
        add si,16
        add di,16
        loop s1
    
    ret

add_128:                ;128位加法,把结果存放到di+16的相对内存中

    push ax
    push cx
    push si
    push di

    mov cx,8
    sub ax,ax
    s0:
        mov ax,[si]
        adc ax,[di]

        mov [di+16],ax
        
        inc si
        inc si
        inc di
        inc di
        loop s0

    pop di
    pop si
    pop cx
    pop ax

    ret






    call show_answer

    mov ax,4c00h
    int 21h


show_answer:
    mov ax,datasg1

    mov ds,ax
    add ax,1
    mov es,ax



    mov bx,36
    mov byte ptr ans[bx],'$'
    dec bx

l2:
    mov si,14
    mov di,14
    call divlong

    add cl,30h
    mov ans[bx],cl
    dec bx

    mov si,0
    mov cx,[si]
    jcxz ok2

    call clr_ex
    
    jmp l2

ok2:

    mov dx,bx
    add dx,32+1
    mov ah,9
    int 21h 

    ret
    






clr_ex:
    push si
    push cx

    mov si,0
    mov cx,8
    l5:
        mov word ptr extra[si],0
        add si,2
        loop l5
    pop cx
    pop si
    ret


divlong:

    mov cx,7
l3:
    push cx

    mov ax,[si-2]
    mov dx,[si]

    mov cx,10
    call divdw

    add es:[di],dx
    add es:[di-2],ax

    mov [si-2],cx
    mov word ptr [si],0

    sub si,2
    sub di,2

    pop cx
    loop l3

    mov cx,[si]
    push cx

    mov cx,16

    mov si,0
    mov di,0
l4:
    mov al,es:[di]
    mov [si],al
    inc si
    inc di
    loop l4

    pop cx

    ret



divdw:  ;算dxax/cx,商dxax余cx

    push bx
    push ax

    mov ax,dx
    mov dx,0
    div cx          ;此时计算 H/N

    mov bx,ax       ;此时bx存放商,dx存放余数

    pop ax
    div cx
    mov cx,dx
    mov dx,bx

    pop bx
    ret 

codesg ends 
end start


①输入部分:接收用户键入的n值经十化二后存入num单元中。

②调用子程序fibp求出FIB(n)的值存放在result单元中。在递归子程序设计中,每次调用可把一帧信息存入堆栈。

l5:
mov word ptr extra[si],0
add si,2
loop l5
pop cx
pop si
ret

divlong:

mov cx,7

l3:
push cx

mov ax,[si-2]
mov dx,[si]

mov cx,10
call divdw

add es:[di],dx
add es:[di-2],ax

mov [si-2],cx
mov word ptr [si],0

sub si,2
sub di,2

pop cx
loop l3

mov cx,[si]
push cx

mov cx,16

mov si,0
mov di,0

l4:
mov al,es:[di]
mov [si],al
inc si
inc di
loop l4

pop cx

ret

divdw: ;算dxax/cx,商dxax余cx

push bx
push ax

mov ax,dx
mov dx,0
div cx          ;此时计算 H/N

mov bx,ax       ;此时bx存放商,dx存放余数

pop ax
div cx
mov cx,dx
mov dx,bx

pop bx
ret 

codesg ends
end start


①输入部分:接收用户键入的n值经十化二后存入num单元中。

②调用子程序fibp求出FIB(n)的值存放在result单元中。在递归子程序设计中,每次调用可把一帧信息存入堆栈。

③输出部分:把运行结果经二化十后在屏幕上显示出来。
  • 0
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验四是关于汇编语言程序的上机过程。汇编语言是一种低级语言,与机器指令一一对应。在上机过程中,我们需要完成以下几个步骤: 首先,需要打开汇编语言编译器软件,如MASM或TASM等。这些软件能够将汇编语言转化为机器指令,实现程序的执行。 接下来,我们需要创建一个新的汇编语言程序文件。可以使用任何文本编辑器,如记事本,编辑器打开并编辑文件。在文件中,我们需要写入汇编语言指令,根据程序的需求来编写。 编写汇编语言程序时,需要确定好程序的功能和流程。在代码中,需要定义变量、数据块,还要使用一些控制结构和算术运算。 在编写完程序后,我们需要将汇编语言程序保存为.asm扩展名的文件。 然后,我们需要使用汇编器软件将程序进行编译。编译的目的是将汇编语言转换为机器指令,以便计算机能够理解和执行。编译成功后,会生成.obj或.obj文件。 最后,我们需要使用链接器软件将编译后的文件与所需的库文件进行链接,生成最终可执行文件。链接的过程会将不同的模块进行整合,确保程序的各个部分能够正确执行。 完成上述步骤后,我们就可以运行汇编语言程序了。运行程序时,计算机会逐条执行汇编语言指令,实现程序的功能。 总结起来,实验四的汇编语言程序上机过程包括打开汇编语言编译器,创建程序文件,编写程序代码,保存文件,进行编译、链接,最后运行程序。这些步骤需要按照顺序进行,才能成功执行汇编语言程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值