汇编语言
是直接在硬件之上工作的编程语言。
PC机及CPU物理结构和编程结构的全面研究——《微机原理与接口》
计算机的一般结构、功能、性能的研究——《计算机组成原理》
如何利用硬件系统的编程结构和指令集有效灵活的控制系统进行工作——《汇编语言》
机器语言
是机器指令的集合。本质是一列二级制数字,计算机将之转变为一列高低电平,驱动计算机的电子器件,进行运算。
计算机是指由CPU和其他受CPU直接或间接控制的芯片、器件、设备组成的计算机系统。如:PC机。
每一种微处理器,(由于硬件设计和内部结构的不同,就需要不同的电平脉冲来控制、工作)都有自己的机器指令集,即机器语言。
书写和阅读机器码程序困难–>汇编语言
汇编语言的主体是汇编指令
。
过程:程序员用汇编语言写出源程序,再用汇编编译器将其编译为机器码,有计算机最终执行。
汇编语言由3类指令组成:
核心
):机器码的助记符,有对应的机器码。CPU
和内存
的关系:要想让CPU工作,必须向它提供存储在内存中的指令和数据。
硬盘
和内存
的关系:硬盘中的数据或指令,必须读到内存中,才能被CPU调用。
CPU如何向内存中读写信息呢?
指令
和数据
,在内存或硬盘上都是二进制信息。
CPU有时把信息看做指令,有时看做数据。
举例:
10001001110110000
89D8H#数据
mov ax,bx#指令
存储器被划分成若干存储单元
,从0开始顺序编号。
一个存储单元的存储信息量
:
单位:位(计算机存储信息的最小单位;bit)、字节(微型存储器容量的最小单位,Byte),1Byte = 8bit
微型计算机存储器的存储单元可以存储一个Byte(字节),即8个bit(二进制位)。
单位换算:1KB=1024B 、1MB=1024KB 1GB=1024B 1TB=1024GB
问题1:CPU如何对内存进行读写操作?
CPU要想进行数据的读写,必须和外部器件(芯片)进行3类信息的交互:
问题2:CPU通过什么将地址、数据和控制信息传到存储器芯片中的呢?
电子计算机能处理、传输的信息都是电信号,电信号当然要用导线传送。计算机中专门连接CPU和其他芯片的导线,通常称为总线。总线,根据传送信息的不同,从逻辑上分为:地址总线、数据总线、控制总线。
问题3:如何命令计算机进行数据的读写呢?
要让计算机或微处理器工作,应向它输入能够驱动它进行工作的电平信息(机器码)。
读操作过程示意图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XZTQUVO2-1612361269413)(F:%5CIT_STUDY%5CBlogs%5Cimg%5C1612096604367.png)]
作用:CPU通过地址总线来指定存储单元。
一个CPU有N根地址总线,则可以说地址总线宽度为N,寻址空间:2^N
作用:CPU与内存或其他器件之间的数据传送通过数据总线进行。
数据总线的宽度决定了CPU和外界的数据传送速度。 N根数据总线一次传送一个N/8B的数据。
作用:CPU对外部器件的控制是通过控制总线来进行的。
控制线是一群不同控制线的集合,控制总线的宽度决定了CPU对外部器件的控制能力。
每个PC机都有一个主板。
主板有一些核心器件和一些主要器件,这些器件通过总线相连。
器件:CPU、存储器、外围芯片组、扩展插槽(一般插有RAM内存条和各类接口卡)等
网卡、显卡、声卡
CPU对外部设备不能直接控制,如:显示器、音箱、打印机等。->接口卡
CPU通过总线向接口卡发送命令,接口卡根据CPU的命令控制外设进行工作。
读写属性分类:
随机存储器(RAM):带电存储,可读可写,关机丢失
只读存储器(ROM):只读不写,断电不丢失
存储器都和总线相连
CPU对他们进行读写时,都通过控制线发出内存读写命令
所有的物理存储器被看作一个由若干存储单元组成的逻辑存储器,即内存地址空间
内存地址空间的大小受CPU地址总线宽度的限制。
对CPU内部构造的理解:一个CPU由运算器、控制器、寄存器等器件构成,这些器件靠内部总线相连。
区分:内部总线与外部总线
不同的CPU,寄存器的个数、结构是不相同的。8086CPU有14个寄存器:AX,BX,CX,DX,SI,DI,SP,BP,IP,CS,SS,DS,ES,PSW
概念?
8086CPU的所有寄存器都是16位的,可以存放两个字节。AX,BX,CX,DX,这四个寄存器通常用来存放一般性的数据,被称为通用寄存器。
8086CPU的通用寄存器都可分为两个独立使用的8位寄存器来用。AX的低八位构成AL寄存器,高8位构成了AH寄存器。
一个16位寄存器所能存储的数据的最大值为多少?2^16-1
字:word,一个字由两个字节组成,高位字节和低位字节。
mov ax,18
mov ah,78
add ax,8
mov ax,bx
add ax,bx
注意:八位寄存器的进位丢失问题
CPU访问内存时,要给出内存单元的地址。所有的内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,即物理地址。
CPU通过地址总线送入存储器,必须是一个内存单元的物理地址。
不同的CPU可以有不同的形成物理地址的方法。
16到底指什么呢?
2.8段的概念
2.9段寄存器
2.10CS和IP
2.11修改CS和IP的指令
2.12代码段
实验1 查看CPU和内存,用机器指令和汇编指令编程
1.[bx]和内存单元的描述
内存信息:①内存单元的地址;②内存单元的长度;
[0]:段地址在ds中,偏移地址为0
[bx]:偏移地址在寄存器中
2.loop指令和循环
3.描述性符号()
4.idata表示常量
mov ax,[bx]
mov [bx],ax
loop实现循环,cx存放循环次数
;计算2^12
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
;将ffff:0006中的数据存入dx中
assume cs:code
code segment
mov ax,0ffffh ;汇编源程序中,数据不能以字母开头
mov ds,ax
mov bx,6 ;ffff:0006
mov al,[bx]
mov ah,0 ;将内存单元中的数据,存入ax中
mov dx,0
mov cx,3
s: add dx,ax
loop s ;累加
mov ax,4c00h
int 21h
code ends
end
g指令:一次执行完标号s前的指令
p指令:自动执行loop
debug中:
mov al,[0]
;al中存放ds:[0]数据
masm中:
mov al,0
mov al,[0]
;等价
masm中正确写法:
mov ax,2000h
mov al,ds:[0]
mov al,ds:[bx]
mov al,[bx]
用同一种方法处理地址连续的内存单元的问题:
;ffff:0 ~ffff:b单元的数据:EA C0 12 00 F0 30 31 2F 30 31 2F 39
;和为:dx:0405h
assume cs:code
code segment
mov ax,0ffffh
mov ds,ax
mov bx,0
mov dx,0
mov cx,12
s: mov al,[bx]
mov ah,0
add dx,ax
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
分析问题的流程:
注意点:
mov ds,0;False
mov al,[0];写法不恰当
可以在访问内存单元的指令中显式地给出内存单元的段地址所在的段寄存器:
mov ax,ds:[bx]
mov ax,ss:[0]
段前缀
:这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的:ds:、 cs:、 ss: 、es: 标识符号
;引起死机
assume cs:code
code segment
mov ax,0
mov ds,ax
mov ds:[26h],ax
mov ax,4c00h
int 21h
code ends
end
实模式和保护模式:
在纯DOS方式(实模式)下,可以不理会dos,直接用汇编语言去操作真实的硬件,因为运行在CPU实模式下的DOS,没有能力对硬件系统进行全面、严格地管理。
但在Windows 2000、Unix这些运行与CPU保护模式下的操作系统中,不理会操作系统,用汇编语言去操作真实的硬件,是根本不可能的。硬件已被这些操作系统利用CPU保护模式所提供的功能全面而严格地管理了。
安全空间:0:200~0:2ff
的256个字节的空间,不存放系统或其他程序的数据或代码。
;将内存ffff:0~ffff:b单元中的数据复制到0:200~0:20b单元中
;ffff:0 ~ffff:b单元的数据:EA C0 12 00 F0 30 31 2F 30 31 2F 39
;0020:0 ~0020:b单元的数据:EA C0 12 00 F0 30 31 2F 30 31 2F 39
assume cs:code
code segment
mov cx,12
mov bx,0
s: mov ax,0ffffh
mov ds,ax
mov dl,[bx]
mov ax,0020h
mov ds,ax
mov [bx],dl
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
引用两个段寄存器(ds、es),减少重复设置段寄存器地址运算:
assume cs:code
code segment
mov ax,0ffffh
mov ds,ax
mov ax,0020h
mov es,ax
mov bx,0
mov cx,12
s: mov dl,[bx];默认ds
mov es:[bx],dl
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
;(1)向内存0:200~0:023f依次传送数据0~63(3fh)
assume cs:code
code segment
mov ax,0020h
mov ds,ax
mov bx,0
mov cx,64
s: mov [bx],bx
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D84Y0iq0-1612361269417)(F:%5CIT_STUDY%5CBlogs%5Cimg%5C1612191134839.png)]
程序取得空间的方法:
如何将数据存储在一组地址连续的内存单元中呢?到哪里去找这段内存空间呢?
;计算0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h的和,结果保存在ax中
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ;定义字型数据,数据在代码段的最开始,大小16字节
mov bx,0
mov ax,0
mov cx,8
s: add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end
-u之后:
cs:0 ~f 中为dw的8个16位的数据;
程序的运行,ip:10h,从而使cs:ip指向程序的第一条指令。
根据什么设置CPU的cs:ip指向程序的第一条要执行的指令?
;程序框架
assume cs:code
code segment
……
数据
start: ……
code ends
end start
;将程序中定义的数据逆置
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ;定义字型数据,数据在代码段的最开始,大小16字节
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;为什么一定呀开辟32字节的内存空间?
start: mov ax,cs
mov ss,ax
mov sp,30h
mov bx,0
mov cx,8
s: push cs:[bx]
add bx,2
loop s
mov bx,0
mov cx,8
s0: pop cs:[bx]
add bx,2
loop s0
mov ax,4c00h
int 21h
code ends
end start
一个段的容量不得大于64kb,8086CPU模式限制
考虑用多个段,来存取数据、代码和栈:
段名就相当于有个标号,它代表了段地址
assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ;定义字型数据,数据在代码段的最开始,大小16字节
data ends
stack segment
dw 0,0,0,0,0,0,0,0
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00h
int 21h
code ends
end start
实验验证了data段、stack段、code段,地址的关系:
x,x+1,,x+2
;实验5-(5):将a段与b段中的数据相加,结果存入c段
assume cs:code
a segment
db 1,2,3,4,5,6,7,8
a ends
b segment
db 1,2,3,4,5,6,7,8
b ends
c segment
db 0,0,0,0,0,0,0,0
c ends
code segment
start: mov ax,a
mov ds,ax
mov ax,c
mov es,ax
mov bx,0
mov cx,8
s: mov al,[bx]
mov es:[bx],al
; mov es:[bx],[bx] ;这种写法不正确
inc bx
loop s
mov ax,b
mov ds,ax
mov bx,0
mov cx,8
s0: mov al,[bx]
add es:[bx],al
inc bx
loop s0
mov ax,4c00h
int 21h
code ends
end start
;实验5-(6):将a段中的前8个字型数据,逆置入b段中
assume cs:code
a segment
dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh
a ends
b segment
dw 0,0,0,0,0,0,0,0
b ends
code segment
start: mov ax,b
mov ss,ax
mov sp,10h
mov ax,a
mov ds,ax
mov bx,0
mov cx,8
s: push [bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start
定位内存单元地址的方法:
and指令:逻辑与指令
作用:将操作对象的相应位设置为0,其他位不变
mov al,01100011B
将第6位设置为0
add al,11011111B
or指令:逻辑或指令
作用:将操作对象的相应位设置为1,其他位不变
mov al,01100011B
将第6位设置为1
or al,00100000B
(1)计算机的二进制信息的表示?
答:计算机对信息进行编码,再解码。只要规则相同,人可以理解的信息就可以存入计算机中,再从计算机中取出。
(2)文本编辑过程——键盘输入a,在屏幕上显示得我过程?
答:
汇编程序中,’……'指明数据以字符形式给出的,编译器将把他们转化为相对应的ASCII码
;汇编程序的字符操作
assume cs:code,ds:data
data segment
db 'unIX'
db 'foRK'
data ends
code segment
start: mov al,'a'
mov bl,'b'
mov ax,4c00h
int 21h
code ends
end start
A:65d 01000001
a:97d 01100001
and: 11011111
结果: 01000001
assume cs:codesg,ds:datasg
datasg segment
db 'BaSiC' ;转小写
db 'iNfOrMaTiOn' ;转大写
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,5
s: mov al,[bx]
; 如果(al)>61H,则为小写字母的ASCII码,则:sub al,20H
and al,11011111b ;小写变大写
mov [bx],al
inc bx
loop s
mov bx,5
mov cx,11
s0: mov al,[bx]
or al,00100000b
mov [bx],al
inc bx
loop s0
mov ax,4c00h
int 21h
codesg ends
end start
assume cs:codesg,ds:datasg
datasg segment
db 'BaSiC'
db 'MinIX'
datasg ends
codesg segment
start: mov ax,datasg
mov ds,datasg
mov bx,0
mov cx,5
s: mov al,[bx]
add al,11011111b
mov [bx],al
mov al,[bx+5]
mov al,5[bx]
or al,00100000b
mov [bx+5],al
loop s
mov ax,4c00h
int 21h
codesg ends
end start
#include
int main(){
char a[5] = "BaSiC";
char b[5] = "MinIX";
int i = 0;
do
{
a[i] = a[i] & 0xDF;
b[i] = b[i] | 0x20;
i++;
} while (i < 5);
printf("%s %s\n",a,b);
getchar();
return 0;
}
SI和DI是8086CPU中和bx功能相近的寄存器,且不能够分成两个8位寄存器来用
将 welcome to masm! 复制到datasg:10h~1fh
assume cs:codesg,ds:datasg
datasg segment
db 'welcome to masm!';16位
db '................'
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,8
s: mov ax,[bx]
mov [bx+16],ax
; inc bx
add bx,2
loop s
mov ax,4c00h
int 21h
codesg ends
end start
assume cs:codesg,ds:datasg
datasg segment
db 'welcome to masm!';16位
db '................'
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax
mov si,0 ;用ds:si指向要复制的字符串
mov di,16 ;用ds:di指向复制的目的空间
mov cx,8
s: mov ax,[si] ;用16位寄存器进行内存单元的数据传送,一次复制2个字节,共复制8次
mov [di],ax
add si,2
add di,2
loop s
mov ax,4c00h
int 21h
codesg ends
end start
[si] [bx]
200 [bx] [si]
[bx] [si].200
深入理解下列几种寻址方式:
[idata]
[bx]
[bx+idata]
[bx+si]
[bx+si+idata]
[bx+idata]:
; 将每一个单词的头一个字母改成大写字母
assume cs:codesg,ds:datasg
datasg segment
db '1. file '
db '2. edit '
db '3. search '
db '4. view '
db '5. options '
db '6. help '
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,6
s: mov al,[3+bx]
and al,11011111b
mov [3+bx],al
add bx,10h
loop s
mov ax,4c00h
int 21h
codesg ends
end start
[bx+si]:
; 将每一个单词的头一个字母改成大写字母
assume cs:codesg,ds:datasg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4 ;设置外层循环计数值
s: mov dx,cx
mov si,0
mov cx,3 ;内层循环的次数
s0: mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop s0
add bx,16
mov cx,dx ;用dx存储的外围循环的计数值恢复cx
loop s
mov ax,4c00h
int 21h
codesg ends
end start
; 将每一个单词的头一个字母改成大写字母dx
assume cs:codesg,ds:datasg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
dw 0
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4 ;设置外层循环计数值
s: mov ds:[40h],cx
mov si,0
mov cx,3 ;内层循环的次数
s0: mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop s0
add bx,16
mov cx,ds:[40h] ;用datasg:40h单元的值恢复cx
loop s
mov ax,4c00h
int 21h
codesg ends
end start
; 使用栈来暂时存储数据
assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
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,datasg
mov ds,ax
mov bx,0
mov cx,4 ;设置外层循环计数值
s0: push cx
mov si,0
mov cx,3
s: mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop s
add bx,16
pop cx
loop s0
mov ax,4c00h
int 21h
codesg ends
end start
[bx+si+idata]:
; 将每一个单词的前4个字母改成大写字母
assume cs:codesg,ss:stacksg,ds:datasg
stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends
datasg segment
db '1. display '
db '2. brows '
db '3. replace '
db '4. modify '
datasg ends
codesg segment
start: mov ax,stacksg
mov ss,ax
mov sp,16
mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4
s: push cx
mov si,0
mov cx,4
s0: mov al,[bx+si+3]
and al,11011111b
mov [bx+si+3],al
inc si
loop s0
add bx,16
pop cx
loop s
mov ax,4c00h
int 21h
codesg ends
end start
本章实践内容较多:
更新中……