汇编语言(王爽)

第一章 基础知识

汇编语言的三类指令

(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

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

小端模式

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

image-20211108161644405

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

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

1地址字单元存放124EH

段地址和[address]

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

mov bx, 1000H

mov ds, bx

mov al, [0]

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

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

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

mov bx,1000H

mov ds,bx

mov[0], al

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

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 指向的内存单元处

image-20211108165651023image-20211108165713824

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

image-20211108170139047

pop ax后

image-20211108170256999

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

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

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

在10000H处写入字型数据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 -->执行

执行结果

image-20211021230304852

第五章 [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中的内容

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

((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, 01100011B

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

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

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

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

mov al, 01100011B

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

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

;将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 01000001 a 61 01100001

B 42 01000010 b 62 01100010

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

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

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

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

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

or al, 00100000B ;将第五位置为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, 11011111B		;将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, 00100000B		;将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]

寻址方式

image-20211115120057989

指令要处理的数据有多长

(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)*10000H+(ax)]/((es)*16+0)的商
	 (dx)=[(dx)*10000H+(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命令查看的截图结论:能否修改,以及,原因分析

img

img

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

实验任务3

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

img

img

实验任务4

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

[复制代码](javascript:void(0)

内容来源于网络如有侵权请私信删除

文章来源: 博客园

原文链接: https://www.cnblogs.com/usercp/p/15556315.html

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!

相关课程

3677 0元 限免