赞
踩
目录
(2)指令“call far ptr 标号”实现的时段间转移
可以控制CPU执行内存中某处代码的指令
可以修改IP、或同时修改CS和IP的指令
按转移行为 | 按指令对IP的修改范围 | 按转移指令 | ||||||
---|---|---|---|---|---|---|---|---|
段内转移 | 段间转移 | 段间短转移 | 段间近转移 | 无条件转移指令 | 条件转移指令 | 循环指令 | 过程 | 中断 |
只修改IP | 同时修改CS和IP | IP修改范围 | JMP | JCXZ | LOOP | |||
jmp ax | jmp 1000:0 | -128~127 | -32768~32768 |
用操作符offset取得标号的偏移地址
格式为:offset 标号
例如:
- assume cs:code
- code segment
- start:
- mov ax,offset start
- ;相当于mov ax,0,标号所在地址为0
- s:mov ax,offset s
- ;相当于mov ax,3,标号所在地址为3
-
- mov ax,4c00h
- int 21h
- code ends
- end start
问题:有如下程序段,添加2条指令,使得该程序在运行中将s处的第一条指令复制到s0处。
assume cs:code
code segment
s:mov ax,bx
mov si,offset s
mov di,offset s0
______________________________
______________________________
s0:nop
nop
code ends
end s
;nop即空,机器码占一个字节,起到占位的作用
分析:
(1)s、s0处的指令所在的内存单元的地址分别是
cs:offset s和cs:offset s0
(2)将s处的数据复制到s0处,等价于
将cs:offset s处的数据复制到cs:offset s0处
(3)地址如何表示?
段地址在cs中,偏移地址在si、di中
(4)要复制的数据有多长?
mov ax,bx指令长度为两个字节,即一个字
补齐代码:
- assume cs:code
- code segment
- s:mov ax,bx
- mov si,offset s
- mov di,offset s0
- mov ax,cs:[si]
- mov cs:[di],ax
- s0:nop
- nop
- code ends
- end s
(1)功能:无条件转移,可以修改IP,也可以同时修改CS和IP
(2)给出的两种信息:转移的目的地址、转移的距离
段间转移(远转移) | jmp 2000:1000 | |
---|---|---|
段内短转移 | jmp short 标号 | IP(-128~127)8位转移 |
段内近转移 | jmp near ptr 标号 | IP(-32768~32767)16位转移 |
JMP short的机器指令中,包含的是跳转到指令的相对位置,而不是转移到目的地址。
- assume cs:code
- code segment
- start:
- mov ax,0
- jmp short s
- add ax,1
- nop
- nop
- s:inc ax
- code ends
- end start
分析:jmp short s指令的读取和执行
(1)(IP)=0003,CS:IP指向EB 05(jmp的机器码)
(2)读取指令码EB 05进入指令缓冲器;
(3)(IP)=(IP)+所读取指令的长度 =(IP)+2 =0005,CS:IP指向add ax,0001;
(4)CPU执行指令缓冲器中的指令EB05;
(5)指令EB05执行后,(IP)=(IP)+05 = 000AH,CS:IP指向inc ax。
如果end start命令错写成ends start,debug挂载的时候则会出现:“access denied” 拒绝挂载的错误提示,编译连接的时候不会提示。
(1)短转移:jmp short 标号
功能:IP=IP + 8位位移
- 8位位移 = 标号处的地址 - JMP指令后的第一个子节的地址
-
- short指明此处的移位是8位位移
-
- 8位位移的范围为-128~127,用补码表示
-
- 8位位移由编译程序在编译时算出
(2)近转移:jmp near ptr 标号
功能:IP = IP + 16位位移
- 16位位移 = 标号处的地址 - JMP指令后的第一个子节的地址
-
- near ptr指明此处的位移为16位位移,进行的是段内近转移
-
- 16位位移的范围为-32769~32767,用补码表示
-
- 16位位移由编译程序在编译时算出
远转移jmp far ptr 标号 | 进转移jmp near ptr 标号 |
段间转移 | 段内转移 |
far ptr指明了跳转到的目的地址,包含了标号的段地址CS和转移地址IP | near ptr指明了相对于当前IP的转移,而不是转移的目的地址 |
assume cs:code code segment start:mov ax.0 mov bx,0 jmp far ptr s db 256 dup(0) s:add ax,1 inc ax code ends end start | assume cs:code code segment start:mov ax,0 mov bx,0 jmp near ptr s db 256 dup(0) s:add ax,1 inc ax code ends end start |
指令格式:jmp 16位寄存器
功能:(IP)=(16位寄存器)
- assume cs:code
- code segment
- start:
- mov ax,0
- mov bx,ax
- jmp bx
- mov ax,0123h
- code ends
- end start
jmp word ptr 内存单元地址 | jmp dword ptr 内存单元地址 |
---|---|
段内转移 | 段间转移 |
从内存单元地址处开始存放着1个字,是转移的目的偏移地址 | 从内存单元地址处开始存放着2个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址 |
mov ax.0123h mov ds:[0],ax jmp word ptr ds:[0] 执行后, (IP)=0123h
mov ax,0123h mov [bx],ax jmp word ptr [bx] 执行后, (IP)=0123h | mov ax,0123h mov ds:[0],ax mov word ptr ds:[2],0 jmp dword ptr ds:[0] 执行后,(CS)=0; (IP)=0123h CS:IP指向0:0123h
mov ax,0123h mov [bx],ax mov word ptr [bx+2],0 jmp dword ptr [bx] 执行后,(CS)=0; (IP)=0123h CS:IP指向0:0123h |
格式:jcxz 标号 (jmp cx ?= zero)
功能:若(cx)= 0,则转移到标号处执行;
若(cx)≠ 0,则什么也不做,程序向下执行。
- (cx)= 0时,(IP)=(IP)+ 8
- 8位位移 = 标号 处的地址 - JCXZ指令后的第一个字节的地址
- 8位位移的范围是-128~123,用补码表示
- 8位位移由编译程序在编译时算出
注释:JCXZ是有条件转移指令
(1)所有的有条件转移指令都是短转移
(2)对IP的修改范围都为-128~127
(3)在对应的机器码中包含转移的位移,而不是目的地址
- assume cs:codesg
- codesg segment
- start:
- mov ax,2000h
- mov ds,ax
- moc bx,0
- s:mov cx,[bx]
- jcxz ok
- inc bx
- inc bx
- jmp short s
-
- ok:mov dx,bx
-
- mov ax,4c00h
- int 21h
- codesg ends
- end start
对IP的修改是根据转移目的地址和转移起始地址之间的位移来进行的
- jmp short 标号
-
- jmp near ptr 标号
-
- jcxz 标号
-
- loop 标号
在它们对应的机器码中不包含转移的目的地址,而是包含的是到目的的地址的位移。
这样的设计,方便程序端在内存中的浮动装配。
调用子程序:call
返回:ret
实质:流程转移指令,它们都修改IP,或者同时修改CS和IP
- mov ax,0
- call s
- mov ax,4c00h
- innt 21h
-
- s:add ax,1
- ret
CPU执行call指令,进行两步操作
- (1)将当前的IP或CS和IP压入栈中
- (SP)=(SP)-2
- ((SS)*16 +(SP))=(IP)
-
- (2)转移到标号处执行指令
- (IP)=(IP)+16位位移
-
- #相当于
- push IP
- jmp near ptr 标号
-
- 注释:
- (1)16位位移 = “标号”处的地址 - call指令后的第一个字节的地址
-
- (2)16位位移的范围是 -32768 ~ 32767,用补码表示
-
- (3)16位位移由编译程序再编译时算出
- call far ptr 标号相当于
- push CS
- push IP
- jmp far ptr 标号
指令“call 标号”类似于“jmp near ptr 标号”,对应的机器指令中为对应于当前IP的转移位移,而不是转移的目的地址,实现段内转移;
指令“call far ptr 标号”实现段间转移。
指令格式:call 16位寄存器
- 相当于进行
- push IP
- jmp 16位寄存器
call word ptr 内存单元地址
- 相当于:
- push IP
- jmp word ptr 内存单元地址
示例:
- mov sp:10h
- mov ax,0123h
- mov ds:[0],ax
- call word ptr ds:[0]
-
- 执行后,(IP)= 0123h,(SP) = 10h-2 = 0eh
call dword ptr 内存单元地址
- 相当于
- push CS
- push IP
- jmp dword ptr 内存单元地址
示例:
- mov 10h
- mov ax,0123h
- mov ds:[0],ax
- ;低地址放偏移地址
- mov word ptr ds:[2],0
- ;高地址放段地址
- call dword ptr ds:[0]
-
- 执行后,(CS)= 0,(IP)= 0123h,(SP)= 0ch
ret指令 | retf指令 | |
---|---|---|
功能 | 用栈中的数据,修改IP的内容,从而实现近转移 | 用栈中的数据,修改CS和IP的内容,从而实现远转移 |
相当于 | pop IP | pop IP pop CS |
举例 | 示例1 | 示例2 |
- ;示例1
- ;p6-1.asm
- assume cs:code,ss:stack
- stack segment
- db 16 dup(0)
- stack ends
- code segment
- mov ax,4c00h
- int 21h
- start:
- mov ax,stack
- mov ss,ax
- mov sp,16
- mov ax,0
- push ax
- mov bx,0
- ret
- code ends
- end start
- ;示例2
- ;p6-2
- assume cs:code,ss:stack
- stack segment
- db 16 dup(0)
- stack ends
- code segment
- mov ax,4c00h
- int 21h
- start:
- mov ax,stack
- mov ss,ax
- mov sp,16
- mov ax,0
- push cs
- push ax
- mov bx,0
- retf
- code ends
- end start
- assume cs:code
- code segment
- main:...
- call sub1
- ;调用子程序sub1
- ...
- mov ax,4c00h
- int 21h
-
- sub1:...
- call sub2
- ;调用子程序2
- ...
- ret
-
- sub2:...
- ...
- ret
-
- code ends
- end main
- ;示例
- ;计算2的N次方方,计算前,N的值由CX给出
- ;p6-3
- assume cs:code,ss:stack
- stack segment
- db 16 dup(0)
- stack ends
- code segment
- start:
- mov ax,stack
- mov ss,ax
- mov sp,16
-
- mov ax,1
- mov cx,3
- call s
- mov ax,4c00h
- add 21h
- s:add ax,ax
- loop s
- ret
- code ends
- end start
mul 寄存器
mul 内存单元
8位乘法 | 16位乘法 | |
---|---|---|
被除数 | AL | AX |
除数 | 8位寄存器或内存字节单元 | 16位寄存器或内存字单元 |
结果 | AX | DX(高位)、AX(低位) |
示例 | mul bl --(ax)=(al)*(bl)
mul byte ptr ds:[0] --(ax)=(al)*((ds)*16+0) | mul word ptr [bx+si+8] --(ax)=(ax)*((ds)*16+(bx)+(si)+8)结果的低16位 --(dx)=(ax)*((ds)*16+(bx)+(si)+8)结果的高16位 |
- ;计算100*10
- mov al,64
- ;100(O) = 64(H)
- mov bl,a
- ;10(O) = a(H)
- mul bl
- ;计算100*10000
- mov ax,64
- ;100 = 64(H)
- mov bx,2710
- ;10000 = 2710(H)
- mul bx
方案
用寄存器传递参数
用内存单元进行参数传递
用栈传递参数
用寄存器来存储参数和结果是最常用使用的方法
编译任务:计算data段中第一组数据的3次方,结果保存在后面一组dword单元中。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |||||||||
- ;p6-4.asm
- ;by c10udz
-
- assume cs:code,ds:data,ss:stack
- stack segment
- db 16 dup(0)
- stack ends
- data segment
- dw 1,2,3,4,5,6,7,8
- dd 0,0,0,0,0,0,0,0
- data ends
- code segment
- start:
- mov ax,stack
- mov ss,ax
- mov sp,16
- mov ax,data
- mov ds,ax
- mov si,0
- mov di,16
-
- mov cx,8
- s:mov bx,[si]
- call cube
- mov [di],ax
- mov [di].2,dx
- add si,2
- add di,4
- loop s
-
- cube:mov ax,bx
- mul bx
- mul bx
- ret
-
- mov ax,4c00h
- int 21h
- code ends
- end start
子程序开始:子程序中使用的寄存器入栈
子程序内容
子程序中使用的寄存器出栈
返回(ret、retf)
编程将给出的数据改为大写格式
- ;p6-9.asm
-
- 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 16 dup(0)
- stack ends
- code segment
- start:mov ax,data
- mov ds,ax
-
- mov ax,stack
- mov ss,ax
- mov sp,16
-
- mov bx,0
- mov cx,4
- s:mov si,bx
- call capital
- add bx,5
- loop s
-
- mov ax,4c00h
- int 21h
-
- capital:push cx
- push si
- s0:mov cl,[si]
- mov ch,0
- jcxz ok
- and byte ptr [si],11011111b
- inc si
- jmp short s0
- ok:pop si
- pop cx
- ret
- ;子程序
-
- code ends
- end start
PSW/FLAGS、别称:程序状态字
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 |
flag寄存器是按位起作用的,它的每一位都有专门的含义,记录特定的信息
1)用来存储相关指令的某些执行结果
2)用来为CPU执行相关指令提供行为依据
3)用来控制CPU的相关工作方式
标志 | 值为1 | 值为0 | 意义 | 备注 | |
---|---|---|---|---|---|
OverFlow | OP | OV | NV | 溢出 | |
Direction | DF | DN | UP | 方向 | down/up |
Sign | SF | NG | PL | 符号 | negative/positive |
Zero | ZF | ZR | NZ | 零值 | |
Parity | PF | PE | PO | 奇偶 | odd/even |
Carry | CF | CY | NC | 进位 |
pushf:将标志寄存器的值压栈
popf:从栈中弹出数据,送入标志寄存器中。
ZF标记相关指令的计算结果是否为0
1)ZF=1,表示“结果为0”,1表示逻辑真
2)ZF=0,表示“结果非0”,0表示逻辑假
PF记录指令执行后,结果的所有二进制位中1的个数
1)1的个数是偶数,PE=1
2)1的个数是奇数,PE=0
指令 | 执行结果 |
---|---|
mov al,1 add al,10 | 结果为0000 1011B = 0000 0001B + 0000 1010B 其中有3个1,则PF=0 |
mov al,1 or al,2 | 结果为0000 0011B = 0000 0001B or 0000 0010B 结果中有2个1,则PF=1 |
SF记录指令执行后,将结果视为有符号数
1)结果为负,SF=1
2)结果为非负,SF=0
另外:有符号数与补码
计算机中有符号数一律使用补码来表示和存储
1)正整数的补码使用二进制表示,与原码相同
2)负数的补码,将其对应的正数二进制的所有位取反,后加一
在进行无符号数运算时,CF记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
CF记录指令执行后,
1)有进位或借位,CF=1
2)无进位或借位,CF=0
在进行有符号数运算的时候,如果结果超过了机器所能表示的范围称为溢出。
OF记录有符号数操作指令执行后,
1)有溢出,OF=1
2)无溢出,OF=0
另外,CF和OF的区别
1)CF是对无符号数运算有意义的进/借位标志位
2)OF是对有符号数运算有意义的溢出标志位
一条指令会带来多个标志寄存器的变化
指令 | CF | OF | SF | ZF | PF |
---|---|---|---|---|---|
sub al,al | 0 | 0 | 0 | 1 | 1 |
mov al,10h | 0 | 0 | 0 | 1 | 1 |
add al,90h | 0 | 0 | 1 | 0 | 1 |
mov al,80h | 0 | 0 | 1 | 0 | 1 |
add al,80h | 1 | 1 | 0 | 1 | 1 |
mov al,0FCh | 1 | 1 | 0 | 1 | 1 |
add al,05h | 1 | 0 | 0 | 0 | 0 |
mov al,7Dh | 1 | 0 | 0 | 0 | 0 |
add al,0Bh | 0 | 1 | 1 | 0 | 1 |
adc是带进位加法指令,它利用CF位上记录的进位值
1)格式:adc 操作对象1,操作对象2
2)功能:操作对象1 = 操作对象1 + 操作对象2+CF
3)例:adc ax,bx实现的功能是:(ax)=(ax)+(bx)+CF
指令 | mov al,98H add al,al adc al,3 | mov ax,1 add ax,ax adc ax,3 | mov ax,2 mov bx,1 sub bx,ax adc ax,1 |
---|---|---|---|
结果 | (al)=34H | (ax)=5 | (ax)=4 |
解释 | =(al)+3+CF =30H+3+1=34H | =(ax)+3+CF =2+3+0=5 | =(ax)+1+CF =2+1+1=4 |
例如:编程计算1EF000H + 201000H,结果放在ax(高16位)和bx(低16位)中
- mov ax,001E
-
- mov bx,F000
-
- add bx,1000
-
- adc,ax,0020
结果:1E F000H + 20 1000H = 3F 0000H
sbb是带进位减法指令,它利用CF位上记录的借位值
1)格式:sbb 操作对象1,操作对象2
2)功能:操作对象1 = 操作对象1 - 操作对象2 - CF
3)例:sub ax,bx实现的功能是:(ax)=(ax)-(bx)-CF
应用:对任意大的数据进行减法运算
例如:计算003E 1000H - 0020 2000H,结果放在ax,bx中
- mov ax,003e
- mov bx,1000
- sub ax,0020
- sbb bx,2000
6.12、cmp和条件转移指令
6.13、条件转移指令应用
6.14、DF标志和串传送指令
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。