📄 汇编004.txt
字号:
高级语言支持,条件字节设置指令
AA.高级语言支持指令,开始于80186,主要是用来简化高级语言的某些特征,总共有3条指令:ENTER,LEAVE,BOUND
a.ENTER,LEAVE,建立与释放堆栈框架命令。在C语言中,栈不仅用来向函数传递入口参数,而且在函数内部的局部变量也存放在栈中。为了准确地存取这些这些局变量和准确地获得入口参数,就需要建立堆栈框架,先看一个小程序:
//C Programming-Language
int sum(int x,int y)
{
int sum;
sum=x+y;
return sum;
}
//The corresponding ASM codes lists below
_sum proc near;注意C语言中函数参数的入栈方式是从右向左,即先是参数y入栈,再是x入栈,再是函数的返回地址入栈
push bp
mov bp,sp;建立堆栈框架
sub sp,2
mov ax,word ptr [bp+4];取参数x
add ax,word ptr [bp+6];加参数y
mov word ptr [bp-2],ax
mov ax,word ptr [bp-2]
mov sp,bp;释放栈框架
pop bp
ret
_sum endp
此时栈顶的示意图是:
|----------------------|
| BP |<====SP
|----------------------|
| 函数返回地址 |<====BP+2
|----------------------|
| 参数x |<====BP+4
|----------------------|
| 参数y |<====BP+6
|----------------------|
| ...... |<====BP+8
|----------------------|
| ........ |<====BP+n,n是一能被2整除的数
|----------------------|
如果用建立和释放堆栈框架指令,那么对应的汇编程序应该是:
_sum proc near
enter 2,0;建立栈框架
mov ax,word ptr [bp+4];取参数x
add ax,word ptr [bp+6];加参数y
mov word ptr [bp-2],ax
mov ax,word ptr [bp-2]
leave;释放栈框架
ret
_sum endp
b.建立栈框架指令ENTER,格式如下:ENTER CNT1,CNT2。其中CNT1表示框架的大小,即子程序中需要放在栈中局部变量的字节数;CNT2是立即数,表示子程序嵌套级别,即从调用框架复制到当前框架的指针数。在立即数CNT2为0时,ENTER指令的实过程是:
PUSH BP
SP=>BP
SP<=SP-CNT1
c.释放栈框架指令LEAVE,其具体实现过程:
8086:
BP=>SP
POP BP
80386:
EBP=>ESP
POP EBP
d.ENTER和LEAVE指令均不影响标志寄存器中的各标志位,同时LEAVE指令只负责释放栈框架,并不负责函数返回。因此,要在LEAVE指令后安排一条返回指令。
BB.条件字节设置指令
这是80386新增的一组指令集,将会在后面全部列表出来。条件字节设置指令的格式:
SETxx OPRD
xx是助记符的一部分,OPRD只能是8位的寄存器或存储单元。
eg:
SETO AL;表示当溢出标志位为1时,即OF=1,将AL置1,否则AL清0
SETNC CH;表示当CF=0时,将CH置1,否则将CH清0
SETNA BYTE PTR [100];表示当AF=0,将DS:[100]这一个字置1,否则将它清0
a.SETZ OPRD;等于0时(ZF=1),置OPRD为1,否则清0
b.SETE OPRD;同a
c.SETNZ OPRD;不等于0时(ZF=0),置OPRD为1,否则清0
d.SETNE OPRD;同c
e.SETS OPRD;为负数时(SF=1)置OPRD为1,否则清0
f.SETNS OPRD;同e正好相反(SF=0)
g.SETO OPRD;OF=1,置OPRD为1,否则清0
h.SETNO OPRD;同g正好相反
i.SETP OPRD;偶(PF=1)置1
j.SETPE OPRD;同i
k.SETNP OPRD;奇(PF=0)置1
l.SETPO OPRD;同k
m.SETB OPRD;低于置OPRD为1,否则清0,这是针对无符号数的
n.SETNAE OPRD;不高于即低于或等于时置OPRD为1,否则清0,这是针对无符号数的
o.SETC OPRD;CF=1,置OPRD为1,否则清0
p.SETNB OPRD;高于或等于时,置OPRD为1,否则清0,这是针对无符号数的
q.SETAE OPRD;高于时置OPRD为1,否则清0,这是针对无符号数的
r.SETNC OPRD;CF=0时,置OPRD为1,否则清0,这是针对无符号数的
s.SETBE OPRD;低于或等于时,置OPRD为1,否则清0,这是针对无符号数的,CF|ZF=1
t.SETNA OPRD;同s,这是针对无符号数的,CF|ZF=1
u.SETNBE OPRD;高于时置OPRD为1,否则清0,这是针对无符号数的,CF OR ZF=0
v.SETA OPRD;同u,这是针对无符号数的,CF OR ZF=0
w.SETL OPRD;小于时,置OPRD为1,否则清0,这是针对有符号数的
x.SETNGE OPRD;同w,这是针对有符号数的
y.SETNL OPRD;大于或等于时,置OPR为1,否则清0,这是针对有符号数的
z.SETGE OPRD;同y,这是针对有符号数的
a1.SETLE OPRD;小于或等于时,置OPRD为1,否则清0,这是针对有符号数的
a2.SETNG OPRD;同a1,这是针对有符号数的
a3.SETNLE;大于时,置OPRD为1,否则清0,这是针对有符号数的
a4.SETG;同a3,这是针对有符号数的
位操作指令,处理器控制指令
AA.位操作指令,8086新增的一组指令,包括位测试,位扫描。BT,BTC,BTR,BTS,BSF,BSR
a.BT(Bit Test),位测试指令,指令格式:
BT OPRD1,OPRD2,规则:操作作OPRD1可以是16位或32位的通用寄存器或者存储单元。操作数OPRD2必须是8位立即数或者是与OPRD1操作数长度相等的通用寄存器。如果用OPRD2除以OPRD1,假设商存放在Divd中,余数存放在Mod中,那么对OPRD1操作数要进行测试的位号就是Mod,它的主要功能就是把要测试位的值送往CF,看几个简单的例子:
b.BTC(Bit Test And Complement),测试并取反用法和规则与BT是一样,但在功能有些不同,它不但将要测试位的值送往CF,并且还将该位取反。
c.BTR(Bit Test And Reset),测试并复位,用法和规则与BT是一样,但在功能有些不同,它不但将要测试位的值送往CF,并且还将该位复位(即清0)。
d.BTS(Bit Test And Set),测试并置位,用法和规则与BT是一样,但在功能有些不同,它不但将要测试位的值送往CF,并且还将该位置位(即置1)。
e.BSF(Bit Scan Forward),顺向位扫描,指令格式:BSF OPRD1,OPRD2,功能:将从右向左(从最低位到最高位)对OPRD2操作数进行扫描,并将第一个为1的位号送给操作数OPRD1。操作数OPRD1,OPRD2可以是16位或32位通用寄存器或者存储单元,但OPRD1和OPRD2操作数的长度必须相等。
f.BSR(Bit Scan Reverse),逆向位扫描,指令格式:BSR OPRD1,OPRD2,功能:将从左向右(从最高位到最低位)对OPRD2操作数进行扫描,并将第一个为1的位号送给操作数OPRD1。操作数OPRD1,OPRD2可以是16位或32位通用寄存器或存储单元,但OPRD1和OPRD2操作数的长度必须相等。
g.举个简单的例子来说明这6条指令:
AA DW 1234H,5678H
BB DW 9999H,7777H
MOV EAX,12345678H
MOV BX,9999H
BT EAX,8;CF=0,EAX保持不变
BTC EAX,8;CF=0,EAX=12345778H
BTR EAX,8;CF=0,EAX=12345678H
BTS EAX,8;CF=0,EAX=12345778H
BSF AX,BX;AX=0
BSR AX,BX;AX=15
BT WORD PTR [AA],4;CF=1,[AA]的内容不变
BTC WORD PTR [AA],4;CF=1,[AA]=1223H
BTR WORD PTR [AA],4;CF=1,[AA]=1223H
BTS WORD PTR [AA],4;CF=1,[AA]=1234H
BSF WORD PTR [AA],BX;[AA]=0;
BSR WORD PTR [AA],BX;[AA]=15(十进制)
BT DWORD PTR [BB],12;CF=1,[BB]的内容保持不变
BTC DWORD PTR [BB],12;CF=1,[BB]=76779999H
BTR DWORD PTR [BB],12;CF=1,[BB]=76779999H
BTS DWORD PTR [BB],12;CF=1,[BB]=77779999H
BSF DWORD PTR [BB],12;[BB]=0
BSR DWORD PTR [BB],12;[BB]=31(十进制)
BB.处理器控制指令
处理器控制指令主要是用来设置/清除标志,空操作以及与外部事件同步等。
a.CLC,将CF标志位清0。
b.STC,将CF标志位置1。
c.CLI,关中断。
d.STI,开中断。
e.CLD,清DF=0。
f.STD,置DF=1。
g.NOP,空操作,填补程序中的空白区,空操作本身不执行任何操作,主要是为了保持程序的连续性。
h.WAIT,等待BUSY引脚为高。
i.LOCK,封锁前缀可以锁定其后指令的操作数的存储单元,该指令在指令执行期间一直有效。在多任务环境中,可以用它来保证独占其享内存,只有以下指令才可以用LOCK前缀:
XCHG,ADD,ADC,INC,SUB,SBB,DEC,NEG,OR,AND,XOR,NOT,BT,BTS,BTR,BTC
j.说明处理器类型的伪指令
.8086,只支持对8086指令的汇编
.186,只支持对80186指令的汇编
.286,支持对非特权的80286指令的汇编
.286C,支持对非特权的80286指令的汇编
.286P,支持对80286所有指令的汇编
.386,支持对80386非特权指令的汇编
.386C,支持对80386非特权指令的汇编
.386P,支持对80386所有指令的汇编
只有用伪指令说明了处理器类型,汇编程序才知道如何更好去编译,连接程序,更好地去检错。
在后续的几篇里将详细介绍80386的段页管理机制及控制寄存器,调试寄存器,以及如何在386实模下和保护模式下编程。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -