Advertisement

汇编语言 知识梳理

阅读量:

@[TOC]目录

寄存器(CPU工作原理)

寄存器(内存访问)

程序

第一章 寄存器(CPU工作原理)

CPU通过总线与外部进行交互操作,内部也有线。
总线分数据总线,地址总线,控制总线。
寻址能力是总线数的2^n。

字节:1
字:2字节

ax,bx因为了继承上版本应用,分ah,al;bh,bl四个,每个8字节,若指令中只有al,则就算需进高位也不可进在ah中。
低位字节在低位,高位在高位。

汇编指令
mov a,b ——a=b
sub a,b —— a=a-b
add a,b——a=a+b
jmp c——ip=c

ip会自动变化,每次ip=ip+所执行字数

物理地址=段地址*16(血汗工厂左移一位)+偏移量
段地址cs
偏移量ip

段的长度只是人为了自己方便画的

debug时:
r:查看寄存器内容 也可以改
例子: r cs
(显示cs)
输入自己想改的值
d:查看
例子:d fff0:0 ff(范围)
e 改写
例子 e b810:0 要改的值
u变成汇编指令
t=跳 就是执行一条指令
a 编呗
例子:地址 用汇编语言写入一个指令

二 寄存器(内存访问)

一、ds和addre

ds:要访问的数据的段地址
mov:1.将数据送入寄存器
2.将一个寄存器的内容送入另一个寄存器
3.把内存单元中的内容送入寄存器
例子:mov al,[0]
(段地址看当时运行情况)
[…]表示偏移地址,他的段地址默认放在ds
注意:mov ds,1000是错误的
8086不支持将数据直接送入段寄存器

所以 数据- >通用寄存器->段寄存器

例子,如何将al的数据送入内存单元10000H?

结论:可行法之一:
mov bx,1000H
mov ds,bx
mov [0],al

二、字的传送
练就完了e r a t

mov,add,sub:
1.mov 寄存器 数据
mov 寄存器 寄存器
mov 寄存器 内存单元
mov 内存单元 寄存器
mov 段寄存器 寄存器
mov 寄存器 段寄存器(可验证)
(要实践哦~

2.add 寄存器,数据
add 寄存器,寄存器
add 寄存器,内存单元
add 内存单元,寄存器
sub 寄存器,数据
sub 寄存器,内存单元
sub 内存单元,寄存器
sub 寄存器,寄存器

(学编程需要探索 挖井)

3.栈 wwwww
以字为单位
寄存器只是一个存储过渡器,不是变量
SS 段寄存器:栈顶段地址
SP 寄存器:存放栈顶的偏移地址
任意时刻,ss,sp指向栈顶元素

push ax时 sp=sp-2
pop ax 时 sp+=2

例子 当栈空 sp指向最高地址单元的下一位地址
10000H-1000FH SS=1000H SP=10H
有一元素 SP=0EH
注意:数据pop依旧存在 只是栈顶指针改变

*栈顶越界问题
只能自己操心

段寄存器以s结尾
通用寄存器以x为结尾
数据段地址永远从ds获得
栈段地址永远从ss获得
代码永远从cs获得

POP和PUSH可以直接对段寄存器使用

xor ax,ax ax置0

出栈顺序和入栈顺序相反

栈段:长度为n,n是16的倍数(划分为栈的范围)

第一个程序

segment ,ends是成对出现的伪指令
伪指令是给编译器看的
ends是段的结束
结尾的end才是真的没了
*勿搞混ends和end

assume 寄存器与段的关联假设

编辑的是源程序
编译后的是程序

标号:一个标号指代一个地址(名称)

程序返回:在程序末尾加上返回的程序段
固定:
mov ax,4c00H
int 21H 中断

语法错误:符号问题,输入拼写问题
逻辑错误:人品问题hhh 不易发现,难以改正,在于经验累积

ctrl+a 全选 Ctrl+s保存 Ctrl+x剪切

程序运行时 ds与cs相差100H,这100H用于创建PSP,进行与操作系统的通讯

程序加载后 ds存放程序所在内存区的段地址

用t执行每一个命令 最后的int 21H用p命令

int 21H执行后,显示“program terminated normall”返回debug中,表示程序正常结束

五 [BX]和loop指令

5.1 [bx]
5.2 loop指令
5.3 在debug中跟踪loop循环
5.4 debug和汇编编译器masm对指令的不同处理
5loop。bx联合
6.段前缀
7.一段安全空间
8.段前缀的应用

bx:[bx]表示一个内存单元,因为masm中[0]不为内存单元,仅仅为0.
例子:
mov bx,0
mov ax,[bx]

()取内容
idata表示常量
例子 mov ax,[idata]

inc(++运算符)
inc bx=bx++

loop 格式 :loop 标号

1、(cx)=(cx)-1
2、判断cx的值,不为零则转至标号处执行,为零则向下执行

通常用loop实现循环功能,cx存放循环次数

例子:assume cs:abc

abc segment
mov ax,2
mox cx,11
s:add ax,ax
loop s

复制代码
    mov ax,4c00H
    int 21H
    
    
      
      
    

abc ends

end

1.cx存放循环次数 ,一定是cx,就像bx一定是偏移地址一样
2.loop的标号一定要放在前面
3。要执行的程序段放在标号和loop之间(循环次数的放置不要放在台前面)

**汇编原程序中禁止以字母开头,要前面加0

debug跟踪:g命令 :例子:若mov ax,4c00 在IP等于0014时 可用 g 0014

用p直接跳到循环结束的地方(后台会循环完)

段前缀:段地址
安全空间0:200-0:2ff

dw:define word 定义字型数据,以逗号隔开,八个字符,分别在偏移0,2,4,8,a,c,e处

指定入口是为了以防程序将数据误读成指令

end:1.通知编译期结束
2,通知入口(CPU将其指作代码段的开头) end后面的

区分数据段、代码段、栈段
一个段64kb(8086)

and按位进行比较
例子:将al第0位设为0:and al,11111110B

or可将某一位设为1
db 定义字节型数据 用单引号
ASCII码大小写区分:小写=大写+32(20H)
注意:大写字母第五位为0,小写字母第五位为1

[bx+idata]做偏移地址(不用inc bx了)
例子:mov ax,[200+bx]
mov ax,[bx+200]
mov ax,200[bx]
mov ax,[bx].200
用[bx+idata]进行数组处理

(与bx相近,但不可分为8位,其他都一样)bx不够用
si与di
例子:db ‘welcome to masm!’
db’…’
后面一行占位
经常si指向原始位置source
di指向复制的目的空间destination

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

mov ax,[bx+si+idata]
mov ax,[idata+bx+si]
mov ax,idata[bx][si]
mov ax,[bx][si].idata
mov ax,[si][bx].idata
(常数在后面加点)

两层循环时外层循环的循环次数cx在进行内存循环时现保存在一个临时寄存器内,在走出内层循环时恢复外层循环的cx

数据暂存的处理:不使用寄存器,而是在内存里面设一个保险箱(在数据段里面定义多一个)
用栈更方便(先push后pop)

汇编语言注释用分号

用bx,bp,si,di来表示存储单元
只可以以4种组合出现:bx+si bx+di bp+si bp+di
bp的段地址默认为ss,帮sp减轻负担

reg表示寄存器 sreg表示段寄存器

idata立即数:立即给出(存放与指令缓冲器)

显性给出寄存器:存储单元的情况可以强行配对

寻址方式
在这里插入图片描述
新方法:例子:mov word ptr ds:[0],1
用word ptr指明指令访问的内存单元是一个字单元
byte ptr为字型单元
注意;push只对字进行操作

[bx+idata+si]访问结构体,用bx定位整个结构体,用idata定位结构体中的某一数据项,用si定位数组项中的每个元素

div 除数放在寄存器或内存单元中8 16
被除数默认放在ax或dx(高字节)和ax(低字节)中16 32(一一对应)
运算除数八位时 商存放在al中 余数在ah中
除数16位时 商存放在 ax中 余数在 dx中

div reg(除数)
div 内存单元

dd:define double word 32位
例子:在这里插入图片描述
dup操作符
例子 db 3 dup(0)
定义三个字节,值为零
相当于db 0,0,0

db 3 dup(0,1,2) = db 0,1,2,0,1,2,0,1,2

无条件转移指令(jmp)
条件转移指令
循环指令(loop)
过程
中断

offset操作符:取得标号的偏移地址
例子 start:mov ax,offset start

jmp 无条件转移(暴力破解),可以只修改IP,也可以同时修改cs和ip
需要两种信息:1、转移的目的地址
2、转移的距离

jmp short 标号 8位位移 段内短转移-128-127 一个字节大小
mov 寄存器 寄存器 只有两个字节

jmp对应机器码不是偏移的目的地 而是向下偏移量

jmp near ptr 标号 16位位移 -32768-32767

jmp far ptr 标号 段间转移 远转移 标号修改 cs与ip 有目的地址的跳转

jmp 16位寄存器 段内转移(近或者短) 16位的偏移地址

jmp word ptr 内存单元地址(段内转移)
jmp dword ptr 内存单元地址(段间转移)

jcxz有条件跳转指令 短转移 位移-128-127 jcxz+标号 若cx为零 跳转

cx :高八位ch 低八位cl

loop:都是短转移
格式:loop 标号
cx=0 啥也不做 与jcxz相反

dec bx=bx–

根据位移进行转移的意义
jmp short 标号
jmp near ptr 标号
jcxz 标号
loop 标号
靠偏移量(为什么?为了方便内存中的浮动装配,就是一部分代码的自由移动,封装调用)

nop:空指令,用于延时等待

⑩call和ret指令(重要,反汇编,函数的调用与返回)

ret:用栈中数据,修改ip内容,从而实现近转移
CPU执行ret指令时,有以下操作:
1、(ip)=((ss)*16+(sp))
2、(sp)=(sp)+2
retf:修改cs和ip内容 实现远转移
1、(ip)=((ss)*16+(sp))
2、(sp)=(sp)+2
3、(cs)=((ss)*16+(sp))
4、(sp)=(sp)+2

ret相当于 pop ip
retf相当于pop ip、pop cs

call常与ret搭配使用,经常有以下两步:
1.将当前ip或cs和ip压入栈中
2.转移(jmp)

call不能实现短转移,除此之外与jmp相同
格式:call 标号*(将当前ip压栈后,转到标号处执行指令)*
操作:
1.(sp)=(sp)-2
((ss)*16+(sp))=(ip)
2、(ip)=(ip)+16位位移(标号地址-call指令后第一个字节的地址)(-32768-32767,用补码表示)

call
1、转移为目的地址
call far ptr 标号
操作:①
1.(sp)=(sp)-2
2、(cs)=((ss)*16+(sp))
3、(sp)=(sp)-2
4、(ip)=((ss)*16+(sp))
② cs=标号所在段地址
ip=标号所在偏移地址

等于push cs
push ip
jmp far ptr 标号

call 16位寄存器
操作:1.(sp)=(sp)-2
2、(cs)=((ss)*16+(sp))
3、(ip)=(16位寄存器)

相当于 push ip
jmp 16位寄存器

转移地址在内存中的call指令
1.call word ptr 内存单元地址
(push ip
jmp word ptr 内存单元地址)

2.call dword ptr 内存单元地址
(push cs
push ip
jmp dword ptr 内存单元地址)
(一般段地址高位h偏移地址地位L)

call和ret的配合使用
call 的下一个指令的ip才是他push进去的ip

call调用子程序(函数)ret返回

mul乘法命令 要么都是8位 要么都是16位
八位乘数的放在aL中和八位寄存器或者内存字节单元
16位的乘数放在ax中和16位寄存器或者内存字单元中

结果:8 _8 放在bx
16_16 放在dx(高位)和ax(低位)中

格式:mul reg
mul 内存单元

参数和结果的传递问题
参数放在bx
结果 ds:ax默认16位相乘

批量数据的传递:用栈

标志寄存器

zf:是否为0 0则zf=1
pf:奇偶位 奇数个一为0 偶数个1为1
sf:符号标志位,负为1,非负为0
cf:flag的第零位 进位标志位 假象更高位(上一条的变化 不是永远的变化)无符号
of:overflow 溢出 有符号

adc:adc ax,bx等同于
ax=add ax+bx+cf(要看前面是sub还是add)
与add配合使用
sbb :sbb ax,bx
ax=ax-bx-cf
cmp:只对标志寄存器影响
cmp ax,ax
则 zf=1
pf=1
sf=0
cf=0
of=0

根据cmp判断
无符号 看zf,cf
有符号 看sf,of,zf

je(cmp时)等于则转移 zf=1 (核心)
jne不等于则转移 zf=0
jb 小于
jnb不小于
ja大于
jna不大于

df标志 方向标志位
df=1 si、di++
0 –
movsb 将ds:si指向的内存单元送入es:di 然后根据df将si、di变化
movsw字
rep movsb 根据cx得数进行repeat
cld将df置零
std 1

popf值
pushf

全部评论 (0)

还没有任何评论哟~