转移指令
可以修改IP或同时修改CS和IP的指令统称为转移指令。
转移指令就是可以控制CPU执行内存中某处的代码的指令……
短转移IP的修改范围: -128~127
近转移IP的修改范围: -32768~32767
8086的CPU转移指令分为以下几类:
无条件转移指令(JMP)
条件转移指令
循环指令(LOOP)
过程
中断
操作符 offset
Debiug ……
offset操作符取得了标号start和s的偏移地址。
复制start指令到s0处
复制的过程……
JMP指令
段间转移、段内短转移、段内近转移
范围是指字节。
jmp short s 段内短转移
jmp near ptr 段内近转移
jmp far ptr s 段间转移
段间转移
机器码: EA0B01490B 是目的地址在指令中的存储顺序。
(存放次序->低地址:高地址)即逆序存放。
低地址16位,高地址16位。
高地址代表转移的段地址,低地址代表偏移量。
0B49:010B 目标转移地址在机器码中段地址与偏移地址是逆序存放,段与偏移地址中的高位与低位也是逆序存放~:)
看来编译器在将指令(不管是高级语言还是汇编),最终全是机器码。
只不过这个机器码,不同的机器码代表不同的指令,机器码后面跟着数据,
这个数据是前或后(带符号数)或是所赋的值,然后CPU执行到当前指令时将当前IP+当前指令的长度,就算出下一条指令的地址,然后将 ip指过去。
这个时候CPU再执行已取回的指令,然后执行。
当遇到要转移的指令时,算出要转移到哪里,然后再次修改IP的值指向转移的地址(无论它是8位还是16位还是32位-段间转移),
然后执行IP所指向的指令。
如果当前执行的指令不是转移指令,则执行完后就执行上一次取这次指令时已修改的IP的值,所以它直接执行就行了。
如果用批处理做一个极简单的编译器,那么一个是机器码(这是固定),机器码后面跟着不同的数据,需要编译器来计算它们前后的位移量。
理论上可以实现(至于批处理文件--文本文件无法直接存二进制数据),
但也不是没有办法~:)
且VBS可以向文件写入二进制数据,那么完全可以用VBS做编译器。
乱想……
简单的说,段内转移,段间转移,近转移这些名词,实际上只不过不同的机器码后面跟着8位(段内近转移),它是带符号数,也就是表示这么多寻址能力,当然是近转移。在CPU看来,只不过是 机器码后面跟着一个8位地址。
而近转移,只不过就是一个机器码后面跟着一个16位的地址数据。
16位所能表示出来的带符号数也就那么多。机器还是一样。
而被MASM编译器喜欢的语法,什么JMP FAR PTR 的段间转移,看这指令太长,到了机器码那里还不是: 机器码,后面跟着32位的地址数据。
而这个地址数据还是按照INTEL喜欢的逆序存放,低位后面是高位。
而那个32位的转移地址也是一样,先低后高,不管它什么段地址:偏移量,
到了最后还是段*16+偏移量,所以那个高位(后面的)自然就是表示段,用低位表示偏移量。反正到了CPU那里最后还是物理地址,这些段和偏移量只不过是读着方便和编程方便,它是给我们方便而看的。
按照书上的解释再举一反三的拔开那些迷雾……
寻找机器码,先看看 mov 指令的机器码与寄存器它们的表示:
Debug分析如下:
得到 MOV AX 的机器码是 B8
MOV BX …… 是 BB
MOV CX …… 是 B9
MOV DX …… 是 BA (这些将来被CPU执行的时候都是二进制0011..所表示的“高”、“低”的电讯号…(先瞎想)
假如要开发向BX寄存器赋 0123H (23存在低位,01存在高位),它们存储状态的表示是 2301H,先读高位再读低位是为了视觉上的方便。而Inter要表示的是低位内存地址存低位,高位内存地址存高位。
现在写 MOV CX 这一个命令的编译器。向CX寄存器赋值 0123H(10进制291)。……(略……)
调用Debug……
理论上相当于
MOV AX,0123
理论上是这样,但Echo不能直接写入二进制到文件。什么语言能写,什么语言就能够实现。
或是
用Debug装入还是 mov ax,0123
转移地址在内存中的jmp指令的两种格式
从内存单元地址处开始存放着一个字,是转移的目的偏移地址。
1) jmp word ptr 内存单元地址(段内转移)
2) jmp dword ptr 内存单元地址(段间转移)
Debug 对比指令
使程序中的jmp指令执行后,CS:IP指向程序的第一条指令,在data段中应该定义哪些数据?
使jmp指令执行后,CS:IP指向程序的第一条指令
假如内存 2000:1000 BE 00 06 00 00 00 ...
跟据下面指令(不运行代码)直接写出结果 (CS)=? IP=?
低位:高位,所以 CS=0006,IP=00BE
JCZX指令
cx=0时退出,8位位移,相当于 if((cx)==0) jmp short 标号。
利用jcxz指令,实现在内存2000H段中查找第一个值为0的字节,找到后将它的偏移地址存储在dx中。
运行前提交“安排”数据
Loop指令
(cx)=(cx)-1 if (cx) 不等于 0 ... (ip)=(ip)+8位有符号数位移。
相当于C表示的: (cx) -- ;
Debug分析代码执行过程……
写视频缓冲区(直接写屏)彩色字符串
运行视图
内存地址: B8000H~~BFFFFH 共32KB的空间,为80*25彩色字符模式的显示缓冲区。它分为8页。
低位:字符ASCII,高位:色值(RGB)二进制表示0~7个位的“开关”。
[ Last edited by redtek on 2006-12-30 at 01:32 PM ]
可以修改IP或同时修改CS和IP的指令统称为转移指令。
转移指令就是可以控制CPU执行内存中某处的代码的指令……
短转移IP的修改范围: -128~127
近转移IP的修改范围: -32768~32767
8086的CPU转移指令分为以下几类:
无条件转移指令(JMP)
条件转移指令
循环指令(LOOP)
过程
中断
操作符 offset
assume cs:code
code segment
start: mov ax,offset start ; 相当于 mov ax,0
s: mov ax,offset s ; 取s标号处的指令偏移地址……
code ends
end start
Debiug ……
0B49:0000 B80000 MOV AX,0000
0B49:0003 B80300 MOV AX,0003
offset操作符取得了标号start和s的偏移地址。
复制start指令到s0处
assume cs:code
code segment
start: mov ax,bx
mov si,offset start
mov di,offset s0
mov ax,cs:
mov cs:,ax
s0: nop
nop
code ends
end start
复制的过程……
-r
AX=0000 BX=0000 CX=0010 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0000 NV UP EI PL NZ NA PO NC
0B49:0000 8BC3 MOV AX,BX
-t
AX=0000 BX=0000 CX=0010 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0002 NV UP EI PL NZ NA PO NC
0B49:0002 BE0000 MOV SI,0000
-t
AX=0000 BX=0000 CX=0010 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0005 NV UP EI PL NZ NA PO NC
0B49:0005 BF0E00 MOV DI,000E
-t
AX=0000 BX=0000 CX=0010 DX=0000 SP=0000 BP=0000 SI=0000 DI=000E
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0008 NV UP EI PL NZ NA PO NC
0B49:0008 2E CS:
0B49:0009 8B04 MOV AX, CS:0000=C38B
-t
AX=C38B BX=0000 CX=0010 DX=0000 SP=0000 BP=0000 SI=0000 DI=000E
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=000B NV UP EI PL NZ NA PO NC
0B49:000B 2E CS:
0B49:000C 8905 MOV ,AX CS:000E=9090
-t
AX=C38B BX=0000 CX=0010 DX=0000 SP=0000 BP=0000 SI=0000 DI=000E
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=000E NV UP EI PL NZ NA PO NC
0B49:000E 8BC3 MOV AX,BX
-t
AX=0000 BX=0000 CX=0010 DX=0000 SP=0000 BP=0000 SI=0000 DI=000E
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0010 NV UP EI PL NZ NA PO NC
JMP指令
段间转移、段内短转移、段内近转移
范围是指字节。
jmp short s 段内短转移
jmp near ptr 段内近转移
jmp far ptr s 段间转移
段间转移
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
0B49:0000 B80000 MOV AX,0000
0B49:0003 BB0000 MOV BX,0000
0B49:0006 EA0B01490B JMP 0B49:010B
机器码: EA0B01490B 是目的地址在指令中的存储顺序。
(存放次序->低地址:高地址)即逆序存放。
低地址16位,高地址16位。
高地址代表转移的段地址,低地址代表偏移量。
0B49:010B 目标转移地址在机器码中段地址与偏移地址是逆序存放,段与偏移地址中的高位与低位也是逆序存放~:)
看来编译器在将指令(不管是高级语言还是汇编),最终全是机器码。
只不过这个机器码,不同的机器码代表不同的指令,机器码后面跟着数据,
这个数据是前或后(带符号数)或是所赋的值,然后CPU执行到当前指令时将当前IP+当前指令的长度,就算出下一条指令的地址,然后将 ip指过去。
这个时候CPU再执行已取回的指令,然后执行。
当遇到要转移的指令时,算出要转移到哪里,然后再次修改IP的值指向转移的地址(无论它是8位还是16位还是32位-段间转移),
然后执行IP所指向的指令。
如果当前执行的指令不是转移指令,则执行完后就执行上一次取这次指令时已修改的IP的值,所以它直接执行就行了。
如果用批处理做一个极简单的编译器,那么一个是机器码(这是固定),机器码后面跟着不同的数据,需要编译器来计算它们前后的位移量。
理论上可以实现(至于批处理文件--文本文件无法直接存二进制数据),
但也不是没有办法~:)
且VBS可以向文件写入二进制数据,那么完全可以用VBS做编译器。
乱想……
简单的说,段内转移,段间转移,近转移这些名词,实际上只不过不同的机器码后面跟着8位(段内近转移),它是带符号数,也就是表示这么多寻址能力,当然是近转移。在CPU看来,只不过是 机器码后面跟着一个8位地址。
而近转移,只不过就是一个机器码后面跟着一个16位的地址数据。
16位所能表示出来的带符号数也就那么多。机器还是一样。
而被MASM编译器喜欢的语法,什么JMP FAR PTR 的段间转移,看这指令太长,到了机器码那里还不是: 机器码,后面跟着32位的地址数据。
而这个地址数据还是按照INTEL喜欢的逆序存放,低位后面是高位。
而那个32位的转移地址也是一样,先低后高,不管它什么段地址:偏移量,
到了最后还是段*16+偏移量,所以那个高位(后面的)自然就是表示段,用低位表示偏移量。反正到了CPU那里最后还是物理地址,这些段和偏移量只不过是读着方便和编程方便,它是给我们方便而看的。
按照书上的解释再举一反三的拔开那些迷雾……
寻找机器码,先看看 mov 指令的机器码与寄存器它们的表示:
mov ax,0000
mov bx,0000
mov cx,0000
mov dx,0000
Debug分析如下:
C:\Masm50>debug
-A
0AF5:0100 MOV AX,0
0AF5:0103 MOV BX,0
0AF5:0106 MOV CX,0
0AF5:0109 MOV DX,0
0AF5:010C
-U 100 109
0AF5:0100 B80000 MOV AX,0000
0AF5:0103 BB0000 MOV BX,0000
0AF5:0106 B90000 MOV CX,0000
0AF5:0109 BA0000 MOV DX,0000
得到 MOV AX 的机器码是 B8
MOV BX …… 是 BB
MOV CX …… 是 B9
MOV DX …… 是 BA (这些将来被CPU执行的时候都是二进制0011..所表示的“高”、“低”的电讯号…(先瞎想)
假如要开发向BX寄存器赋 0123H (23存在低位,01存在高位),它们存储状态的表示是 2301H,先读高位再读低位是为了视觉上的方便。而Inter要表示的是低位内存地址存低位,高位内存地址存高位。
现在写 MOV CX 这一个命令的编译器。向CX寄存器赋值 0123H(10进制291)。……(略……)
调用Debug……
理论上相当于
MOV AX,0123
Echo B82301>Demo.com
理论上是这样,但Echo不能直接写入二进制到文件。什么语言能写,什么语言就能够实现。
或是
chcp 437
echo ╕#☺>a.com
用Debug装入还是 mov ax,0123
转移地址在内存中的jmp指令的两种格式
从内存单元地址处开始存放着一个字,是转移的目的偏移地址。
1) jmp word ptr 内存单元地址(段内转移)
2) jmp dword ptr 内存单元地址(段间转移)
assume cs:code
code segment
start: mov ax,0123h
mov ds:,ax
mov word ptr ds:,0
jmp dword ptr ds: ; 段间转移 Debug: jmp far
mov ax,4c00h
int 21h
code ends
end start
Debug 对比指令
C:\Masm50>debug p170.exe
-r
AX=0000 BX=0000 CX=0015 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0000 NV UP EI PL NZ NA PO NC
0B49:0000 B82301 MOV AX,0123
-u
0B49:0000 B82301 MOV AX,0123
0B49:0003 A30000 MOV ,AX
0B49:0006 C70602000000 MOV WORD PTR ,0000
0B49:000C FF2E0000 JMP FAR
0B49:0010 B8004C MOV AX,4C00
0B49:0013 CD21 INT 21
0B49:0015 05508D ADD AX,8D50
0B49:0018 46 INC SI
0B49:0019 8050E83E ADC BYTE PTR ,3E
0B49:001D 0D83C4 OR AX,C483
-t
AX=0123 BX=0000 CX=0015 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0003 NV UP EI PL NZ NA PO NC
0B49:0003 A30000 MOV ,AX DS:0000=20CD
-t
AX=0123 BX=0000 CX=0015 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0006 NV UP EI PL NZ NA PO NC
0B49:0006 C70602000000 MOV WORD PTR ,0000 DS:0002=9FFF
-t
AX=0123 BX=0000 CX=0015 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=000C NV UP EI PL NZ NA PO NC
0B49:000C FF2E0000 JMP FAR DS:0000=0123
-t
AX=0123 BX=0000 CX=0015 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0000 IP=0123 NV UP EI PL NZ NA PO NC
0000:0123 F0 LOCK
0000:0124 F3 REPZ
0000:0125 EE OUT DX,AL
-q
使程序中的jmp指令执行后,CS:IP指向程序的第一条指令,在data段中应该定义哪些数据?
assume cs:code
data segment
db 0ffh ; 界标置
dw 0
db 0ffh ; 边界标置~:)
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
jmp word ptr
code ends
end start
使jmp指令执行后,CS:IP指向程序的第一条指令
assume cs:code
data segment
dd 12345678h
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
mov ,bx
mov ,cs
jmp dword ptr ds:
code ends
end start
假如内存 2000:1000 BE 00 06 00 00 00 ...
跟据下面指令(不运行代码)直接写出结果 (CS)=? IP=?
mov ax,2000h
mov es,ax
jmp dword ptr es:
低位:高位,所以 CS=0006,IP=00BE
JCZX指令
cx=0时退出,8位位移,相当于 if((cx)==0) jmp short 标号。
利用jcxz指令,实现在内存2000H段中查找第一个值为0的字节,找到后将它的偏移地址存储在dx中。
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
s: mov cl, ; 传送比对是否为0的数据
jcxz ok
inc bx
jmp short s
ok: mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
运行前提交“安排”数据
-d ds:0
2000:0000 FF FF FF 00 FF 00 00 00-00 00 00 00 00 00 00 00
2000:0010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
Loop指令
(cx)=(cx)-1 if (cx) 不等于 0 ... (ip)=(ip)+8位有符号数位移。
相当于C表示的: (cx) -- ;
Debug分析代码执行过程……
assume cs:code
code segment
mov ax,4c00h
int 21h
start: mov ax,0
s: nop
nop
mov di,offset s
mov si,offset s2
mov ax,cs: ; ax=s2地址内容
mov cs:,ax ; cs代码段=s2地址内的指令
s0: jmp short s
s1: mov ax,0
int 21h
mov ax,0
s2: jmp short s1
nop
code ends
end start
写视频缓冲区(直接写屏)彩色字符串
assume cs:code
data segment
db 'welcome to masm!'
data ends
code segment
start: mov ax,data
mov ds,ax
mov ax,0b800h
mov es,ax
mov ah,00000010b
mov di,0 ; 列
mov cx,16
s: mov al,ds:
mov es:,ax
inc ah
inc si ; 读进下一个
add di,2 ; 显示下一列字符
loop s
mov ax,4c00h
int 21h
code ends
end start
运行视图
内存地址: B8000H~~BFFFFH 共32KB的空间,为80*25彩色字符模式的显示缓冲区。它分为8页。
低位:字符ASCII,高位:色值(RGB)二进制表示0~7个位的“开关”。
[ Last edited by redtek on 2006-12-30 at 01:32 PM ]
Redtek,一个永远在网上流浪的人……
_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
