重庆分公司,新征程启航

为企业提供网站建设、域名注册、服务器等服务

汇编语言

汇编语言(王爽)

第一章 基础知识

汇编语言的三类指令

创新互联建站是一家专业提供潞城企业网站建设,专注与网站设计制作、成都网站制作、成都h5网站建设、小程序制作等业务。10年已为潞城众多企业、政府机构等服务。创新互联专业网站建设公司优惠进行中。

(1)汇编指令:机器码的助记符,有对应的机器码

(2)伪指令:没有对应的机器码,由编译器执行,计算机不执行

(3)其它符号,如+,-,*,/等,由编译器识别,没有对应的机器码

指令和数据

在内存或磁盘上,指令和数据没有区别,都是二进制信息

总线

地址总线:一个CPU有N根地址总线,可以说、CPU的地址总线宽度是N,最多可以寻找2的N次方个内存单元

数据总线:宽度决定cpu与外界数据传送速度

控制总线:宽度决定cpu对外部器件的控制能力

第二章 寄存器

CPU的组成

控制器:控制各种器间进行工作

运算器:信息处理

寄存器:进行信息存储

内部总线:连接各种器件,在它们之间进行数据传送

通用寄存器

AX,BX,CX,DX存放一般性的数据,8086cpu寄存器都是16位的,可以存放两个字节(1个字)

AX可以分为AH,AL

8086给出物理地址的方法

(1)在内部用两个16位地址合成的方法形成20位的物理地址

一个称为段地址,一个称为偏移地址

(2)段地址和偏移地址通过内部总线送入地址加法器

(3)地址加法器将两个16位地址合成一个20位的物理地址

​ 物理地址 = 段地址x16+偏移地址

​ 地址加法器将二进制地址左移4位,完成段地址x16

(4)地址加法器通过内部总线将20位物理地址送入 输入输出控制电路

(5)输入输出控制电路将20位物理地址送上地址总线

(6)20位物理地址被地址总线送到存储器

补充:一个x进制的数据左移1位,相当于乘以x

段地址

一个段的起始地址一定是16的倍数,偏移地址16位,代表寻址能力为64KB,故一个段最大长度为64kb

可以用不同的段地址和偏移地址形成同一个物理地址

可以根据需要,将地址连续,起始地址为16的倍数的一组内存单元定义为一个段

CS IP

cs为代码段寄存器,IP为指令指针寄存器

CPU将cs ip指向的内存单元中的内容看作指令,如果说内存中一段信息曾被CPU执行过,

那么,它所在的内存单元必然被cs ip指向过

修改cs ip的指令

mov:传送指令

jump: 用寄存器中的值修改ip

第三章 寄存器(内部访问)

小端模式

高地址内存单元中存放数据高位,低地址存放数据低位

用0,1两个内存单元存放数据4E20H

将起始地址为N的字单元称为N地址字单元,如0地址字单元存放4E20H

1地址字单元存放124EH

段地址和[address]

DS用来存放要访问数据的段地址

mov bx, 1000H

mov ds, bx

mov al, [0]

以上三条指令将H(1000:0)中的数据读到al中

[]表示一个内存单元,0表示内存单元的偏移地址,mov ds,1000H是非法的

需要有一个寄存器进行中转

mov bx,1000H

mov ds,bx

mov[0], al

将al中的数据送入内存单元H中

mov ax,123BH

mov ds, ax

mov al, 0

add al,[0]

add al,[1]

add al,[2]

累加数据段的前三个单元中的数据

段寄存器SS、寄存器SP存放栈顶位置

push ax指令

sp=sp-2,将ax中内容(2266H)送入ss:sp 指向的内存单元处

栈空时,sp指向栈空间最高地址的下一个单元

pop ax后

pop执行后,2266H任然存在,但是已经不在栈中

push 寄存器 ;将一个寄存器中的数据入栈

pop 寄存器 ;出栈,用一个寄存器接收出栈的数据

在H处写入字型数据2266H,不允许 mov 内存单元,寄存器的指令

mov ax, 1000H

mov ss, ax

mov sp, 2

mov ax, 2266H

push ax

第一个汇编程序

;ex1.asm
assume cs:code 
code segment
	dw 0241h,0242h,0243h,0244h,0245h
start:
	mov ax, 0b800h
	mov ds, ax
	
	mov bx, 0
	mov cx, 5
s:	mov ax,cs:[bx]
	mov [bx], ax
	add bx ,2
	loop s
	
	mov ah, 4ch
	int 21h
code ends
end start

masm ex1;-->编译源程序

link ex1;-->链接

ex1 -->执行

执行结果

第五章 [bx]和loop指令

[bx]

mov ax, [bx]

将一个内存单元内容送入ax,内存单元长度为2字节,

偏移地址在bx中,段地址在ds中,相当于 (ax)=((ds)*16+(bx))

mov al, [bx]与之类似

mov [bx], ax

将bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将ax中数据送入内存SA:EA处

((ds)*16+(bx))=(ax)

inc

inc bx含义是bx中的内容加1

mov bx, 1

inc bx

执行后bx=2

()

()用于表示一个寄存器或者一个内存单元里的内容

(ax)表示ax中的内容

(H)表示内存H单元的内容,()中的内存单元地址为物理地址

((ds)*16+(bx))表示:ds中的地址作为段地址add1,bx中的地址为偏移地址add2,

内存add1:add2单元的内容

()中元素可以有三种类型:

  • 寄存器名
  • 段寄存器名
  • 内存单元的物理地址(20位)

idata

用idata表示常量

mov ax, [idata]		;代表mov ax, [1]   mov ax, [2]等

mov ax, idata		;代表mov bx, 1	mov bx, 2 等

但是,在汇编源程序中,想在[]里用idata给出内存单元的偏移地址,就要在[]前面显示

给出段地址所在的段寄存器,否则编译器masm将[idata]视为idata

mov al, ds:[0]

mov al, [0]	;等效与mov al, 0

loop指令

loop指令格式是 :loop 标号,CPU执行loop指令时,需要两步操作

  • (cx)=(cx)-1
  • 判断cx值是否为0,不为0则转至标号处执行,为0则顺序执行

注意:

  • 标号代表一个地址,标号所标识的地址要在前面

  • cx中保存循环的次数

example

assume cs:code
code segment
	mov ax, 2
	
	mov cx, 11
s: 	add ax, ax
	loop s
	
	mov ax, 4c00h
	int 21h
code ends
end

段前缀

用于显式指明内存单元的段地址的 ds: cs: ss: es: 在汇编语言中称为段前缀

mov ax, ds:[bx]

mov ax, cs:[bx]

mov ax, ss:[bx]

mov ax, es:[bx]

mov ax, ss:[0]

mov ax, cs:[0]

结合idata理解

;example

assume cs:code

code segment
	mov ax, 0ffffh
	mov ds, ax			;(ds)=0ffffh
	
	mov ax, 0020h
	mov es, ax			;(es)=0020h
	
	mov bx, 0			;(bx)=0, 此时ds:bx指向ffff:0,es:bx指向0020:0
	
	mov cx, 12			;(cx)=12,循环12次
	
s:
	mov dl, [bx]
	mov es:[bx], dl
	inc bx
	loop s
	
	mov ax, 4c00h
	int 21h
code ends
end

第六章 包含多个段的程序

程序取得空间的方法有两种

  • 在加载程序时候为程序分配
  • 在执行过程中向系统申请

重点讨论第一种

将数据,代码,栈放入不同的段

原因

  • 将数据,栈,代码放入一个段使程序混乱
  • 数据,栈,代码需要的空间可能超过64KB
;example
assume cs:code, ds:data, ss:stack

data segment
	dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h
	
data ends

stack segment
	dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

stack ends

code segment

start:	
	mov ax, stack
	mov ss, ax
	mov sp, 20h			;设置栈顶ss:sp指向stack:20
	
	mov ax, data
	mov ds, ax			;ds指向data段
	
	mov bx, 0			;ds:bx指向data段的第一个单元
	
	mov cx, 8
	
s:
	push [bx]
	add bx, 2
	loop s				;将data段0-15单元中8个字型数据依次入栈
	
	mov bx, 0
	
	mov cx, 8
s0:
	pop [bx]
	add bx, 2
	loop s0				;依次出栈8个字型数据到data段的0-15单元中
	
	mov ax, 4c00h
	int 21h

code ends
end

(1)定义多个段的方法:对于不同的段,要有不同的段名

(2)对段地址的引用:

​ 在程序中,段名相当于一个标号,代表了段地址

​ mov ax, data 含义是将名称为data段的段地址送入ax

(3)代码段,数据段,栈段等的命名,是程序员的安排

​ CPU并不清楚各个段名的意义,data, stack, code 段名只是使程序便于阅读

第七章 更灵活的定位内存地址的方法

and与or指令

通过or指令可以将操作对象的相应位设为0,其它位不变

mov al, 0B

;将al第6位设为0:and al, B

;将al第7位设为0:and al, 0B

;将al第0位设为0:and al, B

通过or指令可以将操作对象相应位设为1

mov al, 0B

;将al第6位设为1:or al, 0B

;将al第7位设为1:or al, B

;将al第0位设为1:or al, 00000001B

以字符形式给出的数据

data segment
	db 'unix'
	db 'foRK'
data ends

上面的源程序中

​ db 'unix' 相当于 db 75H, 6EH, 49H, 58H

​ db 'foRK' 相当于 db 66H, 6FH, 52H, 4BH

mov al, 'a' 相当于mov al, 61H,a的ASCII码为61H

大小写转换问题

大写 十六进制 二进制 小写 十六进制 二进制

A 41 0 a 61 0

B 42 0 b 62 0

观察发现,小写字母的Ascii码比大写字母的ASCII码值大20H

不能通过加减20H的方法改变大小写,因为这种方法需要判断字符是大写还是小写

观察大小写字母的二进制形式,只有第五位不同,

大写字母第五位为0,小写字母第五位为1,可以用and和or实现

and al, B ;将第五位置为0,小写字母->大写字母

or al, 00B ;将第五位置为1,大写字母->小写字母

assume cs:codesg, ds:datasg
datasg segment
	db 'BaSiC'
	db 'iNfOrMaTion'
datasg ends

codesg segment
start:
	mov ax, datasg		
	mov ds, ax				;设置ds指向datasg段
	mov bx, 0				;设置(bx)=0,ds:bx指向'BaSiC'的第一个字母
	
	mov cx, 5				;设置循环次数5,因为'BaSiC'有五个字母
s:
	mov al, [bx]			;将ASCII码从ds:bx所指的单元取出
	and al, B		;将al中ASCII码的第五位置位0,变为大写字母
	mov [bx], al			;将转变后的ASCII码写回原单元
	inc bx
	loop s
	
	mov bx, 5				;设置(bx)=5,ds:bx指向'iNforMaTion'的第一个字母
	
	mov cx, 11				;'iNforMaTion有11个字母,需要循环11次'
	
s0:
	mov al, [bx]
	or al, 00B		;将al中ASCII码第五位置位1,变为小写字母
	Mov [bx], al
	inc bx
	loop s0
	
	mov ax, 4c00H
	int 21h
codesg ends
end start
	
	

[bx+idata]

[bx+idata]表示一个内存单元,它的偏移地址是(bx)+idata (bx中的数值加上idata)

mov ax, [bx+200]含义:将一个内存单元中的内容送入ax,这个内存单元的长度为2个字节,

存放一个字,偏移地址为bx中的数值加上200,段地址在ds中

即:(ax)=((ds)*16+(bx)+200)

该指令也可以写成 mov ax, [200+bx] mov ax, 200[bx] mov ax, [bx].200

[bx+idata]的应用:进行数组的处理

;example

通过比较发现,[bx+idata]的方式为高级语言实现数组提供了便利机制

SI和DI

si和di是8086CPU中和bx功能相近的寄存器,si和di不能分成两个8位寄存器使用

mov bx, 0

mov ax, [bx]

mov si, 0

mov ax, [si]

mov di, 0

mov ax, [di]

以上三组指令实现的功能相同

;用si和di将字符串'welcome to masm'复制到他后面的区域
assume cs:code, ds:data

data segment
	db 'welcome to masm!'
	db '............... '
data ends

code segment
start
	mov ax, data
	mov si, 0
	mov di, 16
	
	mov cx, 8
	
s:
	mov ax, [si]
	mov [di], ax
	add si, 2
	add di, 2
	loop s
	
	mov ax, 4c00h
	int 21h
code ends
end start

;使用[bx+idata]方式优化
code segment
start:
	mov ax, data
	mov ds, ax
	mov si, 0
	mov cx, 8

s:
	mov ax, 0[si]
	mov 16[si], ax
	add si, 2
	loop s
	
	mov ax, 4c00h
	int 21h
code ends
end start

[bx+si]和[bx+di]

mov ax, [bx+si]含义如下:

将一个内存单元中的内容送入ax, 这个内存单元偏移地址位bx中的数值加上si中的数值

段地址在ds中

数学表示:(ax)=((ds)*16+(bx)+(si))

也可以写成 mov ax, [bx] [si]

[bx+si+idata]和[bx+di+idata]

mov ax, [bx+si+idata]含义:将一个内存单元的内容送入ax,

偏移地址为(bx)+(si)+idata,段地址在ds中

数学表示:(ax) = ((ds*16)+(bx)+(si)+idata)

也可以写成 mov ax, [bx+200+si]

​ mov ax, [200+bx+si]

​ mov ax, 200[bx] [si]

​ mov ax, [bx].200[si]

​ mov ax, [bx] [si].200

不同寻址方式的灵活应用

  • [idata]用一个常量表示地址,可以用于直接定位一个内存单元
  • [bx]用一个变量表示内存地址,可以用于间接定位一个内存单元
  • [bx+idata]用一个变量和常量表示地址,可以在一个起始地址的基础上用变量间接定位一个内存单元
  • [bx+si]用两个变量表示地址
  • [bx+si+idata]用两个变量和一个常量表示地址
;

第八章 数据处理的两个基本问题

基本问题

  • 处理的数据在什么地方
  • 要处理的数据有多长

定义描述性符号reg和sreg表示寄存器和段寄存器

reg:ax, bx, cx, dx, ah, al, bh, bl, ch, cl, dh, dl, sp, bp, si, di

sreg: ds, ss, cs, es

bx,si, di和bp

(1)8086cpu中,只有这4个寄存器可以用在[]中进行内存单元的寻址

mov ax, [bx]

mov ax, [bx+si]

mov ax, [bx+di]

mov ax, [bp]

mov ax, [bp+si]

mov ax, [bp+di]

(2)在[]中,这4个寄存器只能单个出现或者以4中组合出现

mov ax, [bx+si]

mov ax, [bx+di]

mov ax, [bp+si]

mov ax, [bp+di]

mov ax, [bx+si+idata]

mov ax, [bx+di+idata]

mov ax, [bp+si+idata]

mov ax, [bp+di+idata]

如mov ax, [bx+bp] mov ax, [si+di]是错误的

(3)[bp]的默认段地址在ss中

mov ax, [bp+si+idata]	;含义:(ax)=((ss)*16+(bp)+(si)+idata)

机器指令处理的数据在什么地方

指令执行前,所要处理的数据可以放在三个地方

  • CPU内部
  • 内存
  • 端口

数据位置的表达

(1)立即数idata执行前放在CPU指令缓存器中

mov ax, 1

add bx, 2000h

(2)寄存器,指令要处理的数据在寄存器中

mov ax, bx

mov ds, ax

push bx

mov ds:[0], bx

push ds

mov ss,ax

mov sp, ax

(3)段地址(SA)和偏移地址(EA)

段地址寄存器可以是默认的

;默认在ds中
mov ax, [0]
mov ax, [di]
mov ax, [bx+8]
mov ax, [bx+si]
mov ax, [bx+si+8]

;默认在ss中
mov ax, [bp]
mov ax, [bp+8]
mov ax, [bp+si]
mov ax, [bp+si+8]

也可以显性给出

mov ax, ds:[bp]
mov ax, es:[bx]
mov ax, ss:[bx+si]
mov ax, cs:[bx+si+8]

寻址方式

指令要处理的数据有多长

(1)通过寄存器名指明要处理数据的尺寸

;字操作
mov ax, 1

mov bx, ds:[0]

mov ds, ax

mov ds:[0], ax

inc ax

add ax, 1000

;字节操作
mov al, 1
mov al, bl
----

(2)用x ptr指明内存单元的长度,x可以为word或者byte

mov word ptr ds:[0], 1

mov byte ptr ds:[0], 1

寻址方式的综合应用

div指令

(1)除数:有8位和16位两种,在一个reg或内存单元中

(2)被除数:默认放在AX或者 DX和AX中,如果除数为8位,被除数则位16位,默认在AX中存放

如果除数为16位,被除数则为32位,在DX和AX中存放,DX存高16位,AX存低16位

(3)结果:如果除数为8位,则AL存储除法操作的商,AH存储余数,(AH是AX的高位)

​ 如果除数为16位,AX存放商,DX存储余数

div byte ptr ds:[0]
含义:(al)=(ax)/((ds)*16+0)的商
	 (ah)=(ax)/((ds)*16+0)的余数
	 
div word ptr es:[0]
含义:(ax)=[(dx)*H+(ax)]/((es)*16+0)的商
	 (dx)=[(dx)*H+(ax)]/((es)*16+0)的余数

伪指令dd

db:定义字节型数据 define byte

dw:定义字型数据 define word

dd:定义双字型数据 define dword

dup

dup是一个操作符,如同db,dw,dd等一样,是由编译器识别处理的,用来进行数据的重复

db 3 dup(0)
;定义了3个字节,它们的值都是0,相当于定义了db 0,0,0

db 2 dup(0,1,2)
;定义了9个字节,相当于db 0,1,2,0,1,2,0,1,2

实验1

用汇编指令编码和调试

实验任务2

给出使用d命令查看生产时期的截图给出使用e命令修改生产日期所在内存单元的截图,以及,修改后,再次使用d命令查看的截图结论:能否修改,以及,原因分析

时间并未被修改,因为生产日期在C0000~FFFFF地址范围内,在其中写入数据是无效的,相当于只改写只读存储器中的内容

实验任务3

给出在debug中使用e命令修改内存单元的命令,及,效果截图给出在debug中使用f命令批量填充内存单元的命令,及,效果截图尝试修改内存单元,或,数据后的效果截图

实验任务4

根据在debug环境中调试观察结果,填空并回答问题。填空注*: 以下这段汇编指令代码,是在debug环境中使用a命令输入的汇编指令。debug环境中,默认十六进制。回答问题

[](javascript:void(0)????

mov ax, 20
mov ds, ax
mov ss, ax
mov sp, 30
push [0] ; 执行后,寄存器(sp) = __002E__
push [2] ; 执行后,寄存器(sp) = _002C___
push [4] ; 执行后,寄存器(sp) = _002A___
push [6] ; 执行后,寄存器(sp) = _0028___
pop [6] ; 执行后,寄存器(sp) = _002A___
pop [4] ; 执行后,寄存器(sp) = _002C___
pop [2] ; 执行后,寄存器(sp) = _002E___
pop [0] ; 执行后,寄存器(sp) = _0030___

[](javascript:void(0)????

问题1:题目要求是把00220H ~ 0022fH用作栈空间。指令mov ss, ax和mov sp, 30执行后,栈顶的逻辑地址和物理地址分别是?

栈顶的逻辑地址:0020:0030 物理地址:00230H*
*

问题2:单步调试到汇编指令push [6]执行结束,pop [6]执行之前,使用d 20:20 2f查看此时栈空间数据,给出实验截图。

问题3:汇编指令pop [0]执行结束后,pop [0]指令执行结束后,使用d命令d 20:0 7查看此时数据空间内的数据是否有变化。给出实验截图。

问题4:如果把最后四条指令改成截图中的顺序,pop [6]指令执行结束后,使用d命令d 20:0 7查看此时数据空间内的数据是否有变化。给出实验截图。

实验任务5

回答问题1和问题2。

问题1:使用t命令单步执行mov ss, ax时,是单步执行完这一条指令就暂停了吗?后面的指令mov sp, 30是什么时候执行的?

不是,两条指令连在一起执行

问题2:根据汇编指令,前三条指令执行后,00220H ~ 0022fH被设置为栈空间。并且,初始时,已通过f命令将初始栈空间全部填充为0。观察单步调试时,栈空间00220H ~ 0022fH内存单元值的变化,特别是图示中黄色下划线表示出的数据值。根据实验观察,尝试思考和分析原因。

栈空间中存放着cs的值073F和ip值0132

实验任务6

给出程序源码给出使用masm、link对程序汇编链接过程截图,以及,运行可执行程序task5.exe的运行结果截图给出在debug中查看task5.exe的程序段前缀PSP的截图。

实验任务7

问题1 给出补全后的完整源码。说明程序中两个空填写的依据。

第一空:将程序的代码段地址赋值给数据段地址.
第二空:先在该位置填0,debug task7.exe之后使用u命令查看mov ax 4c00h这条命令的地址

问题2 在debug中调试,使用g命令将程序执行到loop s之后、mov ax, 4c00h之前,然后,使用u命令对0:200开始的内存单元反汇编,确认是否把task7.asm中line3-line12的代码复制到了目标内存空间。给出使用g命令运行到指定点和使用u命令反汇编0:200到复制代码长度这一段内存空间的截图。

实验2

多个逻辑段的汇编源程序编写与调试

1. 实验任务1

任务1-1

源码

assume ds:data, cs:code, ss:stack 
data segment db 16 dup(0) ; 预留16个字节单元,初始值均为0 
data ends 
stack segment 
db 16 dup(0) ;预留16个字节单元,初始值均为0 
stack ends 
code segment 
start:
mov ax, data mov ds, ax 
mov ax, stack 
mov ss, ax mov sp, 16 ; 设置栈顶 
mov ah, 4ch int 21h 
code ends end start

截图

问题回答

① 在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076A____, 寄存器(SS) =

076B, 寄存器(CS) = 076C

② 假设程序加载后,code段的段地址是X,则,data段的段地址是 x-2, stack的段地址是_x-1

任务1-2

源码

assume ds:data, cs:code, ss:stack

data segment
	db 4 dup(0)		;预留4个字节单元,初始值均为0
data ends

stack segment
 	db 8 dup(0)		;预留8个字节单元,初始值均为0
 stack ends
 code segment
 start:
 	mov ax, data
 	mov ds, ax

 	mov ax, stack
 	mov ss, ax
 	mov sp, 8 		;设置栈顶

 	mov ah, 4ch
 	int 21h
 code ends
 end start

问题回答

① 在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076A____, 寄存器(SS) =

076B____, 寄存器(CS) = 076C__

② 假设程序加载后,code段的段地址是X,则,data段的段地址是_x-2___, stack的段地址是 __ x-1__。

任务1-3

源码

assume ds:data, cs:code, ss:stack

data segment
	db 20 dup(0)	;预留20个字节单元,初始值均为0
data ends

stack segment
	db 20 dup(0)	;预留20个字节单元,初始值均为0
stack ends
code segment
start:
	mov ax, data
	mov ds, ax

	mov ax, stack
	mov ss, ax
	mov sp, 20 		;设置初始栈顶

	mov ah, 4ch
	int 21h
code ends
end start

截图

问题回答

① 在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076A, 寄存器(SS) =

076C, 寄存器(CS) = 076E__

② 假设程序加载后,code段的段地址是X,则,data段的段地址是_x-4___, stack的段地址是___x-2_。

任务1-4

源码

assume ds:data, cs:code, ss:stack
code segment
start:
    mov ax, data
    mov ds, ax

    mov ax, stack
    mov ss, ax
    mov sp, 20

    mov ah, 4ch
    int 21h
code ends

data segment
    db 20 dup(0)
data ends

stack segment
    db 20 dup(0)
stack ends
end start

截图

问题回答

① 在debug中将执行到line9结束、line11之前,记录此时:寄存器(DS) = 076A__, 寄存器(SS) =

076E, 寄存器(CS) = 076A__

② 假设程序加载后,code段的段地址是X____,则,data段的段地址是___x+2_, stack的段地址是

__x+4

任务1-5

基于上述四个实验任务的实践、观察,总结并回答:
① 对于如下定义的段,程序加载后,实际分配给该段的内存空间大小是 16*Math.ceil(N/16)

xxx segment
    db N dup(0)
xxx ends

② 如果将程序task1_1.asm, task1_2.asm, task1_3.asm, task1_4.asm中,伪指令 end start 改成
end , 哪一个程序仍然可以正确执行?结合实践观察得到的结论,分析、说明原因。

答:只有task1_4可以正确执行,实验发现task1_1-1_3的cs中都没有程序的代码了。
原因:没有了伪指令,exe文件被加载在内存中,首先将CS:IP指向程序的首地址。而只task1_4的程序中一开始定义的是代码段,所以CS:IP指向了指令的首地址。task1_1-1_3的程序中一开始定义的是数据段,所以cs:ip指向了数据的首地址而非指令,而CPU会把数据段中的数据当中机器指令来执行。

实验任务2

编写一个汇编源程序,实现向内存单元b800:0f00 ~ b800:0f9f连续160字节,依次重复填充十六进制数

据03 04。

Tips:

  1. 在实验1的实验任务3中,做过达到同样效果的实验。但当时是通过debug的f命令实现填充的。这一

次,要求编程实现。

在debug中,使用f命令,向内存单元批量填写数据。

-f b800:0f00 0f9f 03 04

把内存单元区间b800:0f00 ~ b800:0f9f连续160个字节,依次重复填充十六进制数据03 04

  1. 编程实现时,注意进制问题、字节顺序问题。编写后,运行程序,如果与实验1的实验任务3结果不一

致,说明程序编写有错误。

assume cs:code
code segment
start:mov ax,0b800h
         mov ds,ax
         mov bx,0f00h
         mov cx,80
         mov dx,0403h
      s:mov ds:[bx],dx
         add bx,2
         loop s

         mov ah,4ch
         int 21h
code ends
end start

运行结果

实验任务3

已知8086汇编源程序task3.asm代码片段如下。
task3.asm:

assume cs:code
data1 segment
    db 50, 48, 50, 50, 0, 48, 49, 0, 48, 49 ; ten numbers
data1 ends

data2 segment
    db 0, 0, 0, 0, 47, 0, 0, 47, 0, 0       ; ten numbers
data2 ends

data3 segment
    db 16 dup(0)
data3 ends

code segment
start:
   ; ×××
code ends
end start

要求:
① 编程实现把逻辑段data1和逻辑段data2的数据依次相加,结果保存到逻辑段data3中。
② 在debug中加载、反汇编、调试。在数据项依次相加前,和相加后,分别查看三个逻辑段data1,
data2, data3对应的内存空间,确认逐一相加后,结果的确保存在了逻辑段data3中。
(1)补充完整后的汇编源代码:

assume cs:code
data1 segment
    db 50, 48, 50, 50, 0, 48, 49, 0, 48, 49 ; ten numbers
data1 ends

data2 segment
    db 0, 0, 0, 0, 47, 0, 0, 47, 0, 0       ; ten numbers
data2 ends

data3 segment
    db 16 dup(0)
data3 ends

code segment
start:
   mov ax,data1
   mov ds,ax
   mov bx,0
   mov cx,10
s:mov ax,ds:[bx]
   add ax,ds:[bx+10h]
   mov ds:[bx+20h],ax
   inc bx
   loop s

  mov ah,4ch
  int 21h

code ends
end start

(2)在debug中加载、反汇编、调试截图:

要求给出,在数据项依次相加之前,查看逻辑段data1, data2, data3对应的内存空间数据原始值的
debug命令和截图:

以及,依次相加之后,查看逻辑段data1, data2, data3对应的内存空间数据原始值的debug命令和
截图:

  • 相加前:
  • 相加后:

实验任务4

已知8086汇编源程序task4.asm代码片段如下。
要求:
① 补全程序,实现把逻辑段data1中的8个字数据逆序存储到逻辑段b中。
② 汇编、连接后,在debug中加载程序,运行到line15程序退出前,使用d命令查看数据段data2对应的
内存空间,确认是否实现题目要求。

(1)补充完整后的汇编源代码

assume cs:code

data1 segment
    dw 2, 0, 4, 9, 2, 0, 1, 9
data1 ends 

data2 segment
    dw 8 dup(?)
data2 ends

code segment
start:
    mov ax,data1
    mov ds,ax
    mov ax,data2
    mov ss,ax
    mov sp,16   ;8个字
    mov bx,0
    mov cx,8
s :push ds:[bx]
     add bx,2
     loop s
    mov ah, 4ch
    int 21h
code ends
end start

(2)在debug中加载、反汇编、调试截图

要求给出,在程序退出前,使用d命令查看数据段data2对应的内存空间的截图。

存储前:

查看数据段data2对应的内存空间:

实验任务5

使用任意文本编辑器,录入汇编源程序task5.asm。
(1)task5.asm源码:
task5.asm:

assume cs:code, ds:data
data segment
        db 'Nuist'
        db 2, 3, 4, 5, 6
data ends

code segment
start:
        mov ax, data
        mov ds, ax

        mov ax, 0b800H
        mov es, ax

        mov cx, 5
        mov si, 0
        mov di, 0f00h
s:      mov al, [si]
        and al, 0dfh
        mov es:[di], al
        mov al, [5+si]
        mov es:[di+1], al
        inc si
        add di, 2
        loop s

        mov ah, 4ch
        int 21h
code ends
end start

(2)运行结果截图:

(3)使用debug工具对程序进行调试,使用g命令一次性执行到程序返回前(即ine25执行之后、line27
执行之前)的截图:

(4)源代码中line19的作用是?
AL与DF(1101 1111):把左边第三位清0。
(5)源代码中data段line4的字节数据的用途是?
将line4修改为db 5 dup(2)后的运行结果:

修改为db 5 dup(5)后的结果:

db是伪指令,作用是定义变量的类型为字节型,即每个变量占一个存储单元
db 2,3,4,5,6的作用是:为db后面的每个数字分配一个存储单元。

实验任务6

已知8086汇编源程序task6.asm代码片段如下。
task6.asm:

assume cs:code, ds:data

data segment
    db 'Pink Floyd      '
    db 'JOAN Baez       '
    db 'NEIL Young      '
    db 'Joan Lennon     '
data ends

code segment
start:
   ; ×××
   mov ah, 4ch
   int 21h
code ends
end start

要求:
① 补全程序,将data段中的每行第一个单词从大写->小写。
② 在debug中加载程序,反汇编,执行到line13退出前,用d命令查看data段对应的内存空间,确认每
行第一个单词已经由大写->小写。

(1)task6.asm源代码:

assume cs:code, ds:data

data segment
    db 'Pink Floyd      '
    db 'JOAN Baez       '
    db 'NEIL Young      '
    db 'Joan Lennon     '
data ends

code segment
start:
  mov ax,data
  mov ds,ax
  mov bx,0
  mov cx,4
s:or [bx],byte ptr 00b
  add bx,16
  loop s
  mov ah, 4ch
  int 21h
code ends
end start

(2)在debug中加载、反汇编、调试截图:

要求给出,在程序退出前,使用d命令查看数据段data对应的内存空间的截图。

实验任务7

要求:
① 补全程序,实现题目要求,把年份、收入、雇员人数、人均收入,以结构化方式写入table段中。
表格中,每行数据,在逻辑段table中占16个字节,各项数据占据字节大小分配如下。期中,数据之间用
空格间隔。

(1)task7.asm源码:

assume cs:code, ds:data, es:table

data segment
    db '1975', '1976', '1977', '1978', '1979' 
    dw  16, 22, 382, 1356, 2390
    dw  3, 7, 9, 13, 28 
data ends

table segment
    db 5 dup( 16 dup(' ') )  ;
table ends

code segment
start:
    mov ax,data
    mov ds,ax
    mov ax,table
    mov es,ax

    mov cx,5
    mov si,0
    mov bx,0
s: mov ax,[si]
    mov es:[bx],ax
    mov ax,[si+2]
    mov es:[bx+2],ax
    add bx,10h
    add si,4
    loop s   ;年份

   mov cx,5
   mov si,20
   mov bx,5
s1:mov ax,[si]
    mov es:[bx],ax
    mov ax,0
    mov es:[bx+2],ax
    add bx,16
    add si,2
    loop s1;  ;收入

   mov cx,5
   mov si,30
   mov bx,10
s2:mov ax,[si]
     mov es:[bx],ax
     add bx,16
     add si,2
     loop s2   ;雇员人数

   mov cx,5
   mov si,5
s3:mov ax,es:[si]
     mov bl,es:[si+5]
     div bl
     mov es:[si+8],al
     add si,16
     loop s3   ;求人均收入
    mov ah, 4ch
    int 21h
code ends
end start

(2)调试截图:

(3)查看table段原始数据信息截图:

在debug中运行到程序退出之前,使用d命令查看table段对应的内存空间的截图,确认信息是
否按要求结构化地写入到指定内存

由上图d命令查看信息可知,信息已按要求结构化地写入到了指定的内存中。


网站名称:汇编语言
网页URL:http://cqcxhl.com/article/dsoipei.html

其他资讯

在线咨询
服务热线
服务热线:028-86922220
TOP