- 汇编语言
- 编译和链接
- 进制
- 寄存器
- 通用寄存器
- (地址寄存器)指令寄存器 CS(段地址)和IP(偏移地址)
- 指令的执行过程
- debug
- 寄存器(内存访问)
- 数据段
- 1. 字的存储
- 2.
- 3. mov,add,sub 指令
- 4. -d 段地址:偏移地址
- 5. 在内存中存放自己定义的数据,通过 ds和[] 来 让CPU访问数据
- 代码段
- 1. 段地址存放在cs寄存器中
- 2. 偏移地址存放在ip寄存器当中
- 3. 内存中存放代码
- 4. 修改cs:ip中的值就可使CPU执行代码
- 栈段
- 1. 栈的作用
- 2. 栈的寄存器ss:sp
- 3. 操作指令push&ip
- 4. 处理数据时要 ,临时存放数据
- 5. 修改ss:sp中的值,决定栈顶位置,CPU在执行的过程中把我们定义的栈段当作栈使用
- 6. 一段连续的内存地址
- 7. 栈的容量的最大极限
- 8.每执行 一条 -t 指令 就会将寄存器的值保存到 栈中
- 内存的安全访问
- 承上启下
- 第一个程序
- 编译和链接
- 程序的跟踪 debug + 程序名
- 快速编译
- 偏移地址寄存器 bx
- 自己分配内存
- 定位内存地址的方法
- and 和 or
- 以字符的形式给出数据
- 大小写转换
- [bx+idata]
- SI 和 DI
- [BX+SI] 和 [BX+DI]
- [BX+SI+idata] 和 [bx+di+idata]
- 数据处理的两个基本问题
- bx,si,di和bp
- 指令要处理的数据
- 数据位置的表达
- 数据的长度
- div 指令
- 伪指令 dd (占两个字)
- dup
- 转移指令
- 操作符 offset
- jmp 指令
- jmp short 标号
- jmp near ptr 标号
- jmp far ptr 标号
- 在内存中转移
- jmp word ptr 标号
- jmp dword ptr 标号
- jcxz (短转移)
- loop(短转移)
- ret 和 call
- ret(用栈中的数据)
- call(不能实现短转移)
- 1.根据位移进行转移
- 2.转移目的地址在指令中
- 3.转移地址在寄存器中
- call 和 ret 共同应用
- mul
- 模块化程序设计
- 标志寄存器
- 内中断
- 1.产生
- 2. 中断处理程序
- 3. 中断向量表
- 4.中断的过程
- 5.中断处理程序和iret指令
- 6. 除法错误中断的处理
- 7. 编程处理0号中断
- 端口
- 1. 端口读写指令
- 2.CMOS RAM
- 3.shl,shr
汇编语言
软件安装
1.DOSBox
mount c: d:\asm
c:
//d盘下的文件是自行创建其中包含debug.exe就可以了
2.Vim
-
- 安装完后打开其文件位置
-
- 修改配置文件
在开头写入简单的配置文件
set number
color evening
//保存退出
编译和链接
将源代码 生成最终 的 exe 文件 然后执行
DOSBox代码
masm t1;
link t1;
// t1 为自己创建的asm文件
//在创建txt文件把后缀改为asm
//用vim编辑
asm文件代码
assume cs:code
code segment
mov bx,0B800H
mov es,bx
mov bx,160*10 + 40*2
mov word ptr es:[bx],5535H
mov ax,4C00H
int 21H
code ends
end
进制
10进制
437->>>
\[4* 100+3* 10+7* 1
\] \[4*10^2+3*10^1+7*10^0
\] 0.1.2.3就是他在数字中的位置
2进制
111->>
\[1*2^2+1*2^1+1*2^0$$ >>转换成10进制
\]
进制快速转换
拆分
字节转换
\[1 byte = 8 bit
\] \[1 KB = 1024 byte$$ >> $$1KB = 2^{10} byte
\] \[1 MB = 1024 * 1KB$$ 1MB = 1024 * 1024 byte >> $$1MB = 2^{20} byte
\] \[1 GB = 1024 * 1MB$$ >> $$1GB = 2^{30} byte
\]
小结
- 汇编指令是 机器指令的 注记符,同机器指令一一对应
- 每一种CPU都有自己的汇编指令集
- CPU 可以直接使用的 信息 在存储器中 存放
4.在存储器中指令和数据没用任何区别, 都是二进制数
5.存储器单元从 0 开始 编号
6.一个 存储单元 可以存储 8 个 bit 即 8 为二进制数
7.1byte=8bit 1KB=1024byte 1MB=1024KB 1GB=1024MB
总线
地址总线 决定 CPU 的 寻址能力
数据总线 决定 CPU 的 一次传输数据量
控制总线 决定 CPU 的 对其他器件的控制能力
寄存器
-
小例子
1.1 B800:0400 回车
1.2 1空格 1空格
1.3 2空格 2空格
1.4 ...
-
汇编程序员 就是 通过 汇编语言 中的 汇编指令 去修改 寄存器的值 从而 控制 CPU 控制整个计算机
通用寄存器
AX,BX,CX,DX
- 他们各自可分为两个 8 位寄存器(only)
\[ax=ah+al$$ $$(h==high,l==low)
\]
- 1 byte = 8 bit(8位寄存器)字节型数据
2 byte =16 bit(16位寄存器)字型数据 2个字节
一个字型数据==2个字节型数据=高位字节+低位字
- 数据与寄存器之间 要 保持一致性,8位寄存器给8位数据,16为寄存器给16位数据
不区分大小写
(地址寄存器)指令寄存器 CS(段地址)和IP(偏移地址)
jmp指令 jmp 2000:0 > cs2000,ip=0;
mov ax,1000
jmp ax
==> ip=1000;
只能用jmp指令修改cs,ip
1.CPU从cs:ip 所指的内存单元中读取内容,存取到 指令缓存器当中
2.然后IP跳转到下一个指令位置,并且在执行指令缓存器当中的指令
3.重复1。
| 段地址寄存器 |
偏移地址寄存器 |
| ds(内存),es,ss(栈),cs |
sp(栈),bp,si,di,ip,bx |
指令的执行过程
- CPU从cs:ip所指向的内存单元 读取 指令 然后 存放到 指令缓存器当中
- IP = IP + 所读指令的长度,从而指向下一条指令
- 执行指令缓存器的内容,回到步骤1
debug
-r 查看和修改寄存器中的内容
-r cs
cs value
enter
-d 查看内存中的内容 段地址加偏移地址
-d ss:00
-v 将机器指令翻译成汇编指令
-a 以汇编指令的格式 在内存中写入一条汇编指令 每次debug都的写
-t 执行当前 cs:ip 所指的机器指令 代码段
-e 可以改写 内存中的内容(数据)
-p 快速执行完loop 指令
-g 地址 ==== 一直执行到 地址 的 位置
寄存器(内存访问)
3个段
数据段
1. 字的存储
一次存放两个字节
2.
内存地址由 段地址 和 偏移地址 构成
其中段地址默认保存在DS寄存器当中
偏移地址由 [address] 保存告知
3. mov,add,sub 指令
4. -d 段地址:偏移地址
5. 在内存中存放自己定义的数据,通过 ds和[] 来 让CPU访问数据
代码段
1. 段地址存放在cs寄存器中
2. 偏移地址存放在ip寄存器当中
3. 内存中存放代码
4. 修改cs:ip中的值就可使CPU执行代码
栈段
1. 栈的作用
- 临时性保存数据
- 进行数据交换
-a
mov ax,1000
mov bx,2000
push ax
push bx
pop ax
pop bx
2. 栈的寄存器ss:sp
3. 操作指令push&ip
push 执行过程
1.sp=sp-2(栈顶标记)
2.传入字型数据
pop 执行过程
1.传出字或字节
2.sp=sp+2(栈顶标记)
栈顶标记 在 数据(内存地址)的上面 的 内存地址
sp 偏移地址寄存器 ss 段地址寄存器
4. 处理数据时要 ,临时存放数据
5. 修改ss:sp中的值,决定栈顶位置,CPU在执行的过程中把我们定义的栈段当作栈使用
6. 一段连续的内存地址
7. 栈的容量的最大极限
sp 的变化范围 0~ffffH 32768 个字型数据
call 将指令IP 保存到内存的哪里? ret 可以拿回
保存到栈中 为了让 ret 从栈中取回
8.每执行 一条 -t 指令 就会将寄存器的值保存到 栈中
内存的安全访问
- 安全空间 0:200~0: 2ffH
- 内存分配的时间 1. 系统加载程序的时候 为程序分配的内存。2. 程序执行过程中,向系统再去要内存空间
承上启下
- 我们可以把内存任意的划分为 栈,数据,指令 ,他们可以是同一块内存,亦可以是不同的内存
- cpu 通过 ss:sp 所指向的 内存作为 栈
- ds:[] 所指向的 内存 作为数据
- cs:ip 所指向的 内存 作为指令
指令从哪里?数据从哪来?临时性的数据存放到哪里?
第一个程序
编译和链接
- 编译 masm .mas --> .obj
- 链接 link .obj --> .exe
exe 文件 的描述信息中 保存的程序入口 地址
然后 系统 通过 描述文件 来设置 cs:ip 和 其它内存
asm 文件 -- 汇编语言(1.汇编指令2.伪指令3.符号体系)
- 汇编指令 由编译器 翻译成010101 的机器指令 最后由 CPU 执行
- 伪指令和符号体系 由编译器执行
- 程序返回功能
把系统加载程序的时候 给程序分配的内存 , 设置的寄存器 返还给系统,因为 系统资源 是有限的
mov ax,4c00
int 21H
程序的跟踪 debug + 程序名
-
p 执行 int 指令
-
q 退出
-
cx == 程序长度
-
PSP区 从 ds:0 开始的 256 个字节
快速编译
默认代码(目前)
assum cs:code
code segment
;填写内容
mov ax,4c00H
int 21H
code ends
end
偏移地址寄存器 bx
自己分配内存
自己分配内存
- 一个 segement 最少占据 16 个字节
-
假设 数据段 有 N个字节 则 实际占用 $$(N/16 + 1)*16$$ 个
- 都是 16 的倍数
//实验5
assume cs:codesg
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
codesg segment
start:
mov ax,c
mov es,ax
sub cx,cx
sub bx,bx
add cx,8
addnum: mov ax,a
mov ds,ax
sub dx,dx
mov dl,ds:[bx] ;拿出第一个数据
mov ax,b
mov ds,ax
add dl,ds:[bx] ;拿出第二个数据,并且相加
mov es:[bx],dl
inc bx
loop addnum
mov ax,4c00h
int 21h
codesg ends
end start
总结
定位内存地址的方法
and 和 or
- and 逻辑与 0 置为0
- 全为 1 才出 1 否则全部为 0
- 可用于 对 二进制位的数字 设 0
- or 逻辑或 1 置为1
- 只要有1 就为 1
- 可用于对 二进制数字设 1
以字符的形式给出数据
- like ‘………’ 其中单引号包含的 内容 编译器将把 其中的内容 转化为相应的 ASCII
大小写转换
and 置为大写 1101 1111b
or 置为小写 0100 0000b
[bx+idata]
常用格式
- mov ax,[200+bx]
- mov ax,200[bx]
- mov ax,[bx].200
SI 和 DI
- 类似于BX 但是 不能 分成两个 8 为寄存器
- 全为偏移地址寄存器 bx为基址寄存器
[BX+SI] 和 [BX+DI]
常用格式
mov ax,[bx] [si]
[BX+SI+idata] 和 [bx+di+idata]
数据处理的两个基本问题
sreg 段地址寄存器
reg 寄存器
bx,si,di和bp
指令要处理的数据
- 保存在CPU
- 在内存中
- 在端口中
数据位置的表达
- 立即数(idata)
- 寄存器
- 段地址加偏移地址
数据的长度
在处理数据的时候要 告知 CPU 要处理的数据有多大可以通过一些方法来告知
1. 通过寄存器来指明 如 ax,代表对word操作而 al,代表对byte 操作
2. 无寄存器 则用 X ptr 来表示 X 为byte 或者 word 如 : mov word ptr ds:[0],1
3. 用 push or pop 就不用 声明 因为 栈就是 对字进行操作
div 指令
- 除数 有8位和16位 在一个reg或内存单元中
- 被除数 默认 放在 ax(16位) 或者 dx(高16位) 和 ax(低16位) 中
- 结果 al(商) ah(余数) 或者 ax(商) dx(余数)
伪指令 dd (占两个字)
dup
用来重复数据
- db 3 dup (0) ==> db 0 ,0, 0
转移指令
操作符 offset
jmp 指令
- 无条件转移指令
- 可同时修改 cs 和 ip 或者 ip
jmp short 标号
- 在编译是就已经处理好 要偏移的地址
- 无论 本 命令在哪 只有 偏移地址
jmp near ptr 标号
jmp far ptr 标号
在内存中转移
jmp word ptr 标号
- jmp word ptr ds:[0]
- 只修改 IP
- 段内转移
jmp dword ptr 标号
jcxz (短转移)
- jmp cx zero
- 只有在cx 为0 的情况下 才 执行 转移
loop(短转移)
ret 和 call
通过栈中的数据来修改 cs 和 ip 同时还会 修改栈顶标志
ret(用栈中的数据)
- 近转移 ret 修改 IP pop ip
- \((ip)=((ss)*16+(sp))\)
- \((sp)=(sp)+2\)
- 远转移 retf 修改 cs:ip pop ip,pop cs
- \((ip)=((ss)*16+(sp))\)
- \((sp)=(sp)+2\)
- \((cs)=((ss)*16+(sp))\)
- \((sp)=(sp)+2\)
call(不能实现短转移)
1.根据位移进行转移
push ip
jmp near ptr 标号
2.转移目的地址在指令中
call far ptr
3.转移地址在寄存器中
```assembly
call 16 位 reg
- 执行过程 原理
- call下一条指令的IP压栈后,转到==reg== 处
### 4. 转移地址在内存中
----
#### 1
-----
```assembly
call word ptr 内存单元地址
2
call dword ptr 内存单元地址
call 和 ret 共同应用
批量数据处理
assume cs:code,ds:data,ss:stack
data segment
db 'conversation'
data ends
stack segment
db 16 dup(0)
stack ends
code segment
start: mov ax,data
mov ds,ax
mov si,0
mov cx,12
call capital
mov ax,4c00h
int 21h
capital: and byte ptr ds:[si],11011111b
inc si;
loop capital
ret
code ends
end start
寄存器冲突问题
- 在子程序执行开头,把所需要用到的寄存器压栈
- 在子程序完成后,从栈中弹出各个寄存其的值
assume cs:code,ds:data,ss:stack
data segment
db 'word',0
db 'unix',0
db 'wind',0
db 'good',0
data ends
stack segment
db 128 dup(0)
stack ends
code segment
start: mov ax,data
mov ds,ax
mov cx,4
mov bx,0
s: mov di,bx
call capital
add bx,5
loop s
mov ax,4c00h
int 21h
capital: push cx;执行子程序前压栈
push si
change: mov cl,ds:[si]
mov ch,0
jcxz ok
and byte ptr ds:[si],11011111b
inc si
jmp change
ok: pop si;执行完后弹栈
pop cx
ret
code ends
end start
mul
1. 8位
一个默认放在AL,另一个放在内存字节单元或者8位reg。
结果 默认 AX。
2. 16位
一个默认放在AX,另一个放在内存字单元或者16位reg。
结果 默认 高位在DX ,低位在AX。
模块化程序设计
参数和结果的传递
assume cs:code,ds:data,ss:stack
data segment
dw 1,2,3,4,5,6,7,8
dd 0,0,0,0,0,0,0,0
db 'word',0
db 'unix',0
db 'wind',0
db 'good',0
data ends
stack segment
db 128 dup(0)
stack ends
code segment
start: mov ax,data
mov ds,ax
mov si,0
mov bp,0
call r_start
mov ax,4c00h
int 21h
r_start: mov bx,ds:[si]
call cube
mov ds:[16+bp],ax
add si,2
add bp,4
loop r_start
ret
cube: mov ax,bx
mul bx
mul bx
ret
标志寄存器
-
CF标志位Carry Flag
- 进位(最高位进位)add
- 和运算相关的指令会影响标志位 like add , sub
- 把操作数当作无符号数字
-
ZF标志位Zero Flag
-
判断相等
-
最后结果是否为零
-
PF标志位pairty Flag
-
SF标志位Sign Flag
- 正0负1
- 计算的结果看陈整数和负数
- add sub 影响sf
- mul 不影响sf
-
OF标志位Overflow
- 运算过程中看是否溢出
- 两个操作数都当做有符号 运算过程中决定是否溢出
-
adc 带进位的加法寄存器
-
sbb 带借位减法
-
cmp 比较指令
-
检测比较结果的转移指令
- 和 cmp指令配合使用
-
| 指令 |
含义 |
检测相关的标志位 |
| je |
equal |
zf=1 |
| jne |
not equal |
zf=0 |
| jb |
below |
cf=0 |
| jnb |
not below |
cf=1 |
| ja |
above |
cf=0 && zf=1 |
| jna |
not above |
cf=1 || zf=1 |
-
DF 标志和串传送指令
-
pushf && popf
内中断
1.产生
- 除法溢出
- 单步执行
- 执行into指令
- 执行Int 指令
2. 中断处理程序
3. 中断向量表
- 中断程序的入口地址
- 存放256个中断程序入口地址
- 存放在 0000:0000 到 0000:03FF
- 一个表项占两个字,高->段地址CS 低->偏移地址IP
4.中断的过程
- 取得中断类型码N
- pushf
- TF=0,IF=0
- push CS
- push IP
-
\[(IP)=(N*4),CS=(N*4)+2
\]
- 开始执行中断程序
5.中断处理程序和iret指令
- 中断程序写法的常规步骤
- 保存要用的寄存器
- 处理中断
- 回复寄存器
- 用iret指令返回 --> pop ip,pop cs,pop popf(pop psw)
6. 除法错误中断的处理
1. 出现溢出
2. 产生0号中断信息
3. 执行0号中断
4. 返回操作系统
7. 编程处理0号中断
分析:
- 当发生除法溢出时,产生0号中断信息,从而引发中断过程
- 取得中断类型码N
- pushf
- TF=0,IF=0
- push CS
- push IP
-
\[(IP)=(N*4),CS=(N*4)+2
\]
- 发生0号中断时,Cpu转去执行中断处理程序
- 相关处理
- 向显示缓冲区送字符串
- 返回DOS
- do0
- do0的程序应该放在那里
- 放在0号中断的向量表中0000:0200-0000:02FF
- 中断程序的入口地址放在那里
- cs:0000:0002,ip:0000:0000
总结
- 编写中断处理程序do0
- 将do0送入0000:0200
- 将do0的入口地址送到存储在中断向量表0号表项中
assume cs:code
code segment
start: do0安装程序
设置中断向量表
mov ax,4c00h
int 21h
do0: 显示字符串“overflow”
mov ax,4c00h
int 21h
code ends
end start
端口
1. 端口读写指令
访问端口
in al , 60h;把60h中的数据读入al中
;1.cpu 通过地址线 将地址信息 60h 发出
;2.cpu 通过控制总线发出读命令 选择端口所在的芯片 并通知他 要从中读取数据
;3.端口所在的芯片 将60h端口中的数据通过数据线送入cpu
2.CMOS RAM
3.shl,shr
移位指令
左移--> *2
右移–> \2
来源:https://www.cnblogs.com/bgst007/p/12240237.html |