汇编学习笔记
ps:xxxxxB 表示一串二进制数 xxxxxH 表示一串十六进制数
1.基础知识:
汇编语言
汇编指令 被编译器翻译成 0 机器指令/机器码 由cpu执行
伪指令 由编译器执行的
符号体系 由编译器执行的
ex:
内存地址 十六进制指令 汇编指令 数据
073F:0100 7403 JZ 0105
073F:0102 E99700 JUMP 019C
1KB = 1024byte 2^10 = 1024
1MB = 1024KB
1GB = 1024MB
地址线 和 数据线 和 控制线:
CUP读取内存中的内存地址和数据通过 地址线 和 数据线 和 控制线:
地址线 读取内存地址 地址线的根数决定读取的地址的大小(寻址能力) 32根地址线的寻址能力为2^32=4GB (32位操作系统) 数据线 读取数据 数据线的根数决定读取的数据的大小 控制线 控制读取、写入
讯享网
内存:
RAM 允许读取和写入 断电后,指令和数据就丢失了
讯享网ROM 只允许读取 断电后,指令和内存还存在,一般用于计算机启动
端口:
CPU 通过端口来访问外接设备 鼠标键盘等:
端口 port 港口 用来装货和卸货 这里的货指数据 端口号 60H 就是端口号 input out指令 和端口有关 读取 写入 控制线 读写信息
汇编语言 针对cpu的 地址线 数据线 控制线
cpu中一定有可以存放 地址信息 和数据 信息的地方 ——寄存器
我们汇编程序员 就是 通过 汇编语言 中的 汇编指令 去 修改 寄存器里的内容
从而 控制 cpu 就可以 控制整个计算机了
MOV AX,0005 AX就是一个数据寄存器
073F:0100 7403 JZ 0105
DS ES SS CS 都是 冒号左边的 一种 地址信息 IP比较像冒号右边的
2.debug调试工具的使用
讯享网 u指令——可以将内存中的 机器指令 翻译成 汇编指令 d指令——可以 查看 内存中的内容 r指令—— 可以 查看 和 修改寄存器的值 e指令——可以 修改 内存单位的内容 a指令——可以 以汇编指令的格式 在内存中写入 机器指令 t指令—— 执行 当前 cs:ip 所指向的 机器指令 p指令——执行汇编程序,单步跟踪。与T指令不同的是:P指令 不会跟踪进入子程序或软中断。p指令还可以用于结束 本次循环,进入下一次循环 g指令——执行汇编指令。(指令从开始运行到目标指令为止, 前面的所有指令都会被执行)
程序的跟踪
debug + 程序名(带.exe)
-u 查看指令
-t 单步执行
!!!!注意 需要用 -p 执行 int 指令
-q 退出(退出debug,回到DOS状态)
运行程序时cx寄存器的值为程序的长度(单位是字节)
-g指令
-g[=起始地址] [断点地址] ("[ ]"代表可选参数)
意思是从起始地址开始执行到断点地址。
如果不设置断点,则程序一直运行到中止指令才停止。
8086 CPU中 在任意时刻,cpu将CS,IP 所指向的内容 全部当作指令来执行:
在内存中 指令和数据 是没有区别的,都是二进制信息,
是我们汇编程序员 通过修改 寄存器里的内容(地址寄存器),告诉cpu
数据在哪里 指令在哪里。
!!!!CS 和 IP 决定了CPU从哪里开始读取指令!!!!
指令的执行过程
1,cpu从cs:ip 所指向的内存单元读取指令,存放到 指令缓存器中,
2,ip = ip + 所读指令的长度,从而指向 下一条指令,
3,执行指令缓存器中的内容,回到步骤1
3.寄存器:
数据寄存器:
AX
BX 也可以被当作 偏移地址寄存器
CX cx也有其他作用
DX ax,dx 用来处理数据的
因为他们有一个特殊的地方 是其他寄存器 所没有的
通用寄存器,存放数据的,数据寄存器
他们可以各自分割为2个8位寄存器
AX = AH + AL AX的高8位构成 AH寄存器 H=high
BX = BH + BL AX的低8位构成 AL寄存器 L=low
CX = CX + CL
DX = DH + DL 0000 0000 ~ 1111 1111 或者 0~FF 或者 0~255
256种状态
8086CPU 一次性可以 处理 2种尺寸的数据
地址寄存器:
地址信息 也可以当成一种数据
| 段地址: | 偏移地址 |
|---|---|
| ds: | sp |
| es: | bp |
| ss: | di |
| cs: | ip |
0000 0000 0000 0000 0000 ~ 1111 1111 1111 1111 1111 或 0~fffffH
地址加法器 地址计算方式
段地址 x 16(10H)+ 偏移地址(0~ffffH) = 物理地址
段地址 x 16 = 基础地址
基础地址 + 偏移地址 = 物理地址
ex:
段地址 : 偏移地址
F230H X10H + C8H = F23C8H
如果偏移地址需要超过ffffH,则无法找到物理地址
ES寄存器
段地址寄存器 类似DS寄存器和数据相关
SI和DI寄存器
类似 bx寄存器,不过这两个寄存器不能分成两个8位寄存器
特殊用法:
[bx+si/di+5] (里面的顺序可以调换) 但是 不能像[bx+si+di] 这样用
标志位寄存器: ——flag寄存器
它是一个16位寄存器,有16个二进制位,有的位置上具有对应的标志位
8086CPU中的flag寄存器的各个位含义:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
OF DF IF TF SF ZF AF PF CF
标志位的取值 与运算指令(ex:add,sub,inc,mul,div,or,and等)有关,
与传送指令(ex:mov,push,pop等)无关
!!!!inc指令不影响CF标志位!!!!!
真值表
| 标志 | 真值为1 | 假值为0 |
|---|---|---|
| OF | OV | NV |
| SF | NG | PL |
| ZF | ZR | NZ |
| PF | PE | PO |
| CF | CY | NC |
| DF | DN | UP |
CF
英文:carry flag 进位标志位(针对无符号运算)、
将两个操作数都当作无符号数进行运算
它的真值CY 英文 carry yes 表示有进位
它的假值CN 英文 carry no 表示没有进位
*CF标志位还能表示是否借位
ZF
英文 :zero flag 零标志位
它的真值ZR 英文 zero 表示结果为0
它的假值NZ 英文 not zero 表示结果不为0
PF
英文:parity flag 奇偶校验标志位
它的真值PE 英文 parity even 表示结果为偶数
它的假值PO 英文 parity odd 表示结果为奇数
取值是看二进制中的1的个数是奇数还是偶数.
ex: 00000011B–3,具有偶数个1,PF标志就是PE
SF
英文: sign flag 符号标志位(正负标志位)
它的真值NG 英文 negative 表示结果为负数
它的假值PL 英文 plus 表示结果为正数
OF
英文:overflow flag 溢出标志位(针对有符号运算)
将两个操作数都当作有符号数进行运算
它的真值 OV 英文 overflow 表示结果溢出
它的假值 NV 英文 not overflow 表示结果无溢出
DF
英文 :direction flag 方向标志位
它的真值 DN 英文 down 表示每次串传递操作后,si,di递增
它的假值 UP 英文 up 表示每次串传递操作后,si,di递减
-128~127 ;有符号
-32768~32767 ;结果超过这个范围为溢出
4.寄存器(内存的访问)
ds段地址寄存器 访问数据用的
mov al,ds:[0]
mov al,ds:[1]
mov ds:[0],ax
mov ds:[1],bh
(debug中需要省略ds:,只用写mov al,[0],mov [0],ax)
数据段 ——编程时候的一种数据安排
字节型数据 字型数据 在内存中的存放
字型数据 在内存中存储时,需要2个地址连续的内存单元存放,
cpu和内存之间的交互注意点:
1.数据从哪里来 内存地址
2.数据的长度 字节型数据 字型数据
3.寄存器是相互独立的
数据和指令的区别:
本质是没有区别,都是一串二进制数字
CS:IP 读取的 当作指令
DS:[偏移地址] 读取的 当作数据
程序员 去修改 寄存器中的内容 从而决定 数据从哪里来,指令从哪里来
5.栈
栈的概念: 一段连续的内存单元,也就是一段连续的内存地址
内存角度:
入栈 push 将16位寄存器 或者 内存中的 字型数据 -> 栈顶标记上方,修改栈顶标记
出栈 pop 将栈顶标记 所标识的 字型数据 -> 16位寄存器 或者 内存中,修改栈顶标记
ex:
push ax 修改SP寄存器中的数值 SP = SP - 2
将 AX 中 字型数据 -> SS:SP 所组合出来的 内存地址中 入栈
栈的设置:
栈的大小最好设置成16(byte)的倍数,防止出现一些 稀奇古怪的 问题
栈顶越界:
入栈或出栈的 指令或数据的数量 超过栈的大小,即栈顶越界
该操作 会导致 一连串的错误(ex:原来栈中的数据被覆盖)
所以 在编程过程中用到栈时 需要特别注意,安排好栈的大小。
栈的最大空间可以设置为多少
SP寄存器的变化范围 0~ffffH 一共65536个字节,32768个字型数据,即64kb
栈的作用:
内存段的安全问题 数据段 代码段 栈段
随意地向某一段内存空间中 写入内容 是非常危险的
使用 操作系统 分配给你的 内存空间
在操作系统的环境中,合法的通过 操作系统取得的 内存空间 都是安全的
因为操作系统不会让一个程序 所使用的 内存空间 和 其他程序 以及系统
自己的 空间 产生 冲突 ,操作系统可以看作是一个管理内存的程序。
程序的编译与链接
exe 可执行文件
系统是怎么知道 要分配多大的内存 给 这个 程序的? 也就是这个exe
这些信息称为描述信息
系统就是根据这些描述信息 进行 相关的设置
mam编译规则
data segment 告诉了编译器 data 段 从这里开始
data ends 告诉了编译器 data 段 在这里结束 为了分配内存
段的名字可以随意取,这里取作data,是为了方便阅读和理解
我们在编写.asm文件时,不加H默认为10进制,加H表示为16进制,若像4c00
不加H,编译时报错Non-digit in number,因为不加H默认为10进制,
而10进制中是不允许出现字母的,也有些编译器要求以0x开头表示16进制
编写.asm时使用到 [bx] 时可以完整的打出 ds:[bx] 或者省略 ds:,直接打 [bx]
在debug中 mov ax,[0] = mov ax,ds:0 ,而在masm编译器中会被翻译成
mov ax,[0] = mov ax,0。结果截然不同,所以避免使用 [数字] ,用 [bx] 代替,
或者 用 段寄存器:[数字] 代替(ex:ds:[0])。
程序返回的功能
因为内存是有限的,所以程序返回是必要的
程序段前缀数据区(PSP区)
从ds:0 开始的256个字节
它是用来 系统和程序之间 进行的通信,里面包含 程序的名字,程序中的代码
程序区 ds+10H:0
物理地址: (ds + 10H)x 10H + 0 = ds x 10H + 100H
(PSP区和程序区在内存上是连续的)
6.汇编指令及伪指令 总结:
汇编指令MOV——移动指令 将XX数据移动到XX寄存器中,
或者将XX寄存器(中的数据)移动到另一个寄存器中
在使用 mov 时 要保证 数据与 寄存器之间 位数一致性
ex:
mov ax,4e20H
mov ah,ffH
mov bx,ax
mov cl,bl
mov dl,bh
mov ax,dx
!!!! 数据与寄存器之间要 保证一致性!!!!!
8位寄存器 给 8位寄存器 8位数据 给 8位寄存器
16位寄存器 给 16位寄存器 16位数据 给 16位寄存器
汇编指令ADD——加法指令
ex: add ax,0008H —— ax = ax + 0008H
将逗号左边的值与逗号右边的值相加,再将结果存入逗号左边
ex: add ax ,bx—— ax =ax + bx
SUB——减法指令
英文单词 subtract
ex sub ax,0008H—— ax = ax - 0008H
将逗号左边的值减去逗号右边的值,再将结果存入逗号左边
ex sub ax,cx—— ax =ax -cx
汇编指令——[BX]和LOOP指令:
指令 inc bx = add bx,1 不过这个指令占用的内存更少,节约了内存
loop指令 2个步骤
- 先cx = cx -1
- 后判断cx中的值,不为0 则跳转(jmp)到 标号(内存地址)的 位置 继续执行
若 cx = 0,则执行下面的 指令
ex:
mov cx,16
mov dl,0
s: mov ds:[bx],dl
inc dl
inc bx
loop s
mov ax,4c00H
int 21H
s:——标号
执行到指令loop s 时 先让cx的值减一,然后判断cx中的值是否为0,不为零,
跳转到 标号开始处 的代码 开始执行:mov ds:[bx],dl,inc dl,inc bx
然后又执行到 loop s,再先将cx -1 ,然后判断x中的值是否为0,重复
以上操作,直到 cx = 0 ,跳出循环,改为执行loop s下方的代码,
mov ax,4c00h ,int 21h。
dw
英文单词是 define word 定义字型数据(一个数据占2个字节)
ex: dw 0001h,0002h,0003h(数据之间用逗号隔开)
dw 作用 不仅是定义了一串存放在cs:0处的 字型数据,还可以为该程序开辟一段
内存空间 。
ex:dw 0,0,0,0,0,0,0,0 为该程序开辟了一段 16个字节 的空间
db
英文单词是 define byte 定义字节型数据(一个数据占1个字节)
end
结束程序的伪指令
后面跟上标号,可以描述程序的入口(即程序从哪里开始执行)
ex:
assume cs:code
code segment
dw 1,2,3,4,5,6,7,8
start: mov ax,0
mov bx,0
mov cx,8
a: mov ax,cs:[bx]
add bx,2
loop a
mov ax,4c00H
int 21h
包含多个段的程序:
一个段(segment)最小占用16个字节,占用的字节总是 16的倍数
汇编指令 and 和 or
(逻辑运算指令:按照二进制位进行逻辑运算)
and 与运算 作用:将操作对象的相应位置设为0,其他位不变
ex:mov ax,0b
and ax, 00b
执行后:ax = 00b (两个全为1,结果才为1) 串联
or 或运算 作用: 将操作对象的相应位设成1,其他位不变
ex:mov ax,0b
or ax,00b
执行后:ax=0b (两个只要有一个为1,结果就为1) 并联
word ptr和byte ptr 伪指令
确定数据的大小(长度)的方法
word ptr 16位标志
byte ptr 8位标志
ex: mov word ptr ds:[0],1 将16位的1(0001)放入ds:[0]处
mov byte ptr ds:[0],1 将8位的1(01)放入ds:[0]处
Inc word ptr ds:[0 将ds:[0]处的数据加上一个16位的1
汇编指令 div指令 除法指令
除数:有8位和16位两种,在一个 寄存器 或者 内存单元中
被除数:默认放在 AX 或者 AX 和 DX 中
如果除数为8位,被除数则为16位 ,默认存放在 AX中
如果除数为16位,被除数则为32位,DX存放高16位,AX存放低16位
结果:
如果除数为8位,则AL(低位)储存除法操作的商,AH(高位)储存除法操作的余数
如果除数为16位,则AX储存除法操作的商,DX储存除法操作的余数
ex:div bl
div byte ptr ds:[0]
div dx
div word ptr ds:[1]
dd伪指令
定义double world 数据(32位/8个16进制位)
dup伪指令
重复定义数据
格式: 数据长度类型 重复次数 dup (重复的数据)
ex: dw 100 dup(1) 定义100个dw类型的0
ex: db 3 dup(0,1,2) 定义db类型的0,1,2三遍(一共9个db数据)
ex: db 2 dup (‘abc’,‘ABC’) 定义’abc’,'ABC’字符串两遍(一共4个字符串12个字节)
OFFSET 操作符 (由编译器处理)
功能:取得标号处的偏移地址
汇编指令——jmp 指令
英文单词 jump
转移指令, 可以修改 cs 和 ip 这2个寄存器 决定了cpu从哪里读取指令
ex:
jmp 2000:0
jmp 寄存器
*在编写asm文件时 jmp 后面还可以跟上标号,编译器会自动将标号 翻译成对应标号处的地址
jmp指令 要给出 两种信息:
1.利用标号使用jmp:
8位位移 -128~127 jmp short xx 段内短转移
16位位移 -32768~32767 jmp near ptr xx 段内近转移(xx表示标号)
这两种jmp只修改ip寄存器
(实际上是利用位移来转移)
位移 = 标号处偏移地址地址 - jmp指令后一个字节的偏移地址
ex:0010 - 0002 = 0008(取byte)= 08 jmp short xx 机器码为 EB08
ex:0103 - 0003 = 0100(取word)= 0100 jmp near ptr xx 机器码为E90001
无限制位移范围 jmp far ptr xx 这种jmp同时修改cs和ip寄存器
2.无标号使用jmp:
jmp word ptr 内存单元地址(段内转移)
ex: mov ax,0123h
mov ds;[0],ax
jmp word ptr ds:[0]
结果 (ip)= 0123h
jmp dword ptr 内存单元地址(段间转移)
结果:(cs)= 目标地址+2 ;(ip) = 目标地址
ex: mov ax,0123h
mov ds:[0],ax
mov word ptr ds:[2],0
jmp dword ptr ds:[0]
结果(cs)= 0 ;(ip)= 0123h
计算机中是没有减法的,减法在计算机内是用加上一个负数表示的
负数的是正数通过补码的方式进行转变的
补码的方式:将一个正数 变成二进制后 按位取反(0->1/1->0)最后再加上1
ex:-5=5进行补码=00000101—>+1==FB
汇编指令——jcxz 指令
短转移指令 修改ip寄存器 范围 -128~127
格式: jcxz 标号(如果(cx)= 0,转移到标号处执行)
jcxz 标号 = if((cx)== 0 )jmp short 标号
汇编指令 CALL 和 RET
call指令
call ——调用指令,类似调用函数,遇到ret回到调用点处
位移的方式 将转移的目的地址存放在内存中
call 标号 = push ip + jmp near ptr 标号
指令执行过程:
1.cpu从cs和ip寄存器所组合出来的地址中 读取指令 将其读到 指令缓存器中
2.ip = ip + 所读指令的字节数
3.执行 指令缓存器的内容,回到第一步
call 指令原理
{将位移保存在机器码中
将转移的目的地址存放在内存中
将转移的目的地址存放在机器码中 call far ptr s
将转移的目的地址存放在寄存器中 call ax,call bx}
利用call指令实现调用子程序,记得分清 局部变量 和 全局变量
ret指令
ret 执行该指令 相当于执行了 pop ip
retf 执行该指令 相当于执行了 pop ip 和 pop cs
汇编指令 mul ——乘法指令
两个相乘数 要么都是 8位 要么都是 16位 分为 8位乘法 和 16位乘法
8位乘法:
一个数字默认存放在 al 中 另一个数字 存放在 其他 8位寄存器中
或者 字节型内存单元中
ml 8位寄存器 意思是 al * 8位寄存器里的值
mul byte ptr ds:[0] 意思是 al * byte ptr ds:[0]中的值
结果:得到一个16位数值 存放在 ax 中
16位乘法:
一个数字默认存放在 ax 中 另一个数字 存放在 其他 16位寄存器中
或者 字型内存单元中
mul 16位寄存器 意思是 ax * 位寄存器里的值
mul word ptr ds:[0] 意思是 ax * word ptr ds:[0]中的值
结果:得到一个32位数值 低存放在 ax 中 高16位存放在dx中
汇编指令 adc
英文意思:add carry ——带进位的加法(适用于大于16位的加法)
adc ax,bx 执行后 (ax)=(ax)+(bx)+CF(cf位里的值0/1)
对比 add ax,bx 执行后 (ax)=(ax)+(bx)
ex:要实现 1EF000H + H
结果的低16位存放在ax中,高16位存放在dx中
代码: mov ax,F000H
mov dx,001EH
add ax,1000H
adc dx,0020H
汇编指令 sbb
带借位的减法 类似adc(适用于大于16位的减法)
汇编指令 cmp
英文:compare 比较
执行cmp后将两个操作数相减,但是不保存结果,只改变标志位
对比sub指令:sub ax,bx 执行后 (ax)= (ax)-(bx)
cmp ax,bx 执行后 不改变ax的值(ax),
仅通过(ax)-(bx)的结果来,修改标志位(zf,cf,sf,of)
cmp ax,bx 的不同情况 讨论:
1.ax = bx —— zf = 1 代表ax,bx相等
2.ax != bx —— zf = 0 代表ax不等于bx
3.ax < bx —— cf = 1 代表ax小于bx
4.ax >= bx —— cf = 0 代表ax大于等于bx
5.ax > bx —— cf = 0 且 zf = 0 代表ax大于bx
6.ax <= bx —— cf = 1 或 zf = 1 代表ax小于等于bx
汇编指令 je,jne,ja,jna,jb,jnb
条件跳转指令,常与cmp指令配合使用(类似高级语言的if)
注意:以上跳转指令都是短跳转,即跳转范围为-128~127
jne jump not equal 如果不相等则跳转 zf=0
ja jump above 如果大于则跳转 cf=0且zf=0
jna jump not above 如果不大于则跳转(小于等于) cf=1或zf=1
jb jump below 如果小于则跳转 cf = 1
jnb jump not below 如果不小于则跳转(大于等于) cf = 0
汇编指令 cld,std
设置DF标志位值的指令
汇编指令 movsb,movsw
串传送指令
汇编指令 rep
重复指令
根据 cx 的值 重复执行后面的指令
汇编指令 pushf 和 popf
pushf:将flag寄存器中的值保存在栈中
popf: 将栈中的值取出存入flag寄存器中
!这两个指令是直接使用的,不带任何的操作数
7.内中断
发生了需要CPU立刻去处理的信息
1.除法错误 divide overflow 中断信息
2.单步执行
3.执行into指令
4.执行int指令
中断向量表 存放在内存 0000:0000~0000:03FF中
中断类型码
0号处理中断信息的程序地址 cs:ip 0
1号处理中断信息的程序地址 cs:ip 1
2号处理中断信息的程序地址 cs:ip 2
… … …
CPU通过 中断类型码 找到中断向量表 中 与之对应的 程序地址的 位置
中断过程
1.取得中断类型码 N
2.保存标志位寄存器 =》 栈 pushf
3.将标志位寄存器的第8位 TF 和 第9位 IF 设置为0
4.push cs
5.push ip
6.cs = N * 4 + 2 ip = N *4
中断处理程序返回的办法:
iret (pop ip
pop cs
popf)
对比ret(pop ip)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/39597.html