前言
在计算机编程的世界里,汇编语言扮演着一种特殊而重要的角色。它是一种低级语言,直接与计算机硬件进行交互,提供了对计算机体系结构底层操作的直接控制。在汇编语言中,“转移” 是一项基本而关键的操作,它使得程序能够灵活地改变执行的流程,实现分支和循环等基本结构。其中,offset 操作符和 JMP 指令是在汇编中常用于实现转移的两个关键元素。
汇编中的“转移”综述:
“转移” 在汇编语言中是一种机制,允许程序在执行过程中跳转到其他位置继续执行。这种能力使得程序能够根据不同的条件或需要,选择性地执行特定的代码块。在这个过程中,涉及到两个主要元素:offset 操作符和 JMP 指令。
操作符 offset:
offset 操作符用于获取标签或变量在代码段中的偏移量。这个偏移量表示标签或变量相对于代码段的起始地址的位置。通过 offset,程序能够动态地处理内存中的数据和执行跳转等操作。这为编程提供了更大的灵活性,使得代码能够更容易地适应不同的情境和需求。
JMP 指令:
JMP 指令是汇编语言中的跳转指令,用于改变程序的执行流程。通过 JMP,程序可以无条件地跳转到指定的地址,实现代码的非顺序执行。这是实现循环、条件分支等逻辑的基础,为程序的控制流提供了关键的控制点。
一、转移综述
1.1 :背景:
一般情况下指令是顺序地逐条执行的,而在实际中,常需要改变程序的执行流程。
1.2 转移指令
可以控制CPU执行内存中某处代码的指令
可以修改IP,或同时修改CS和IP的指令
1.3 转移指令的分类
按转移行为
段内转移:只修改IP,如jmp ax
段内转移(Jump within a Segment):
当我们只需要在当前代码段内进行跳转时,我们使用段内转移。这就像是在当前程序的一本书中的不同章节之间翻页。例如,jmp ax 指令就是一种段内转移。这里,ax 寄存器中存储的值将被直接加载到指令指针寄存器(IP),从而控制程序跳转到 ax 寄存器所指示的内存地址。
段间转移:同时修改CS和IP,如jmp 1000:0
段间转移(Jump between Segments):
有时候我们需要从一个代码段跳转到另一个代码段,就像是关闭一本书并打开另一本一样。这时,我们使用段间转移。例如,jmp 1000:0 指令就是一种段间转移。这里,1000 是新的代码段的地址,而 0 是该段内的偏移地址。同时,指令指针寄存器(IP)会被设置为 0,代码段寄存器(CS)则会被设置为 1000,这样程序就会从新的代码段开始执行。
总的来说,这些跳转指令是为了使程序能够按照我们的设计在不同的部分之间流动,从而实现更复杂的逻辑和功能。
根据指令对IP修改的范围不同
段内短转移:IP修改范围为-128~127
在汇编语言中,段内转移可以分为两种:短转移和近转移,它们主要是根据转移的范围不同而区分的。
段内短转移(Short Jump within a Segment):
短转移是一种限制在较小范围内的跳转,它的目的是在当前代码段内进行跳转。IP(指令指针寄存器)的修改范围是 -128 到 127。这就像是在一本小册子的一页上进行跳转,适用于相对较短的代码段。例如,jmp short label 就是一种短转移指令。这里 short 关键字表示这是一个短跳转。
段内近转移:IP修改范围为-32768~32767
段内近转移(Near Jump within a Segment):
近转移是一种更广泛的跳转,允许在当前代码段内进行更大范围的跳转。IP 的修改范围是 -32768 到 32767。这就像是在一本厚重的书中的章节之间进行跳转,适用于相对较大的代码段。例如,jmp near label 就是一种近转移指令。
总的来说,短转移和近转移的区别在于它们允许的跳转范围大小不同。选择使用哪一种取决于你的程序的结构和需求,以便更有效地管理程序的执行流程。
二、操作符offset
2.1 offset操作符是干什么的?
在汇编语言中,offset 操作符用于获取一个标签(label)或变量在代码段中的偏移量。这个偏移量表示标签或变量相对于代码段的起始地址的位置。
标号是什么?
在汇编语言中,标号(label)是一种用于标识代码位置的符号。你可以把标号看作是程序中的地标或标记,帮助程序员更容易地定位和引用特定的代码块或数据。
举个例子,如果你有一个循环的开始处,你可以在那里放置一个标号,类似于这样:
start_of_loop: ; 这里是循环的代码 ; ... jmp start_of_loop ; 跳转回循环开始处
在这个例子中,start_of_loop 就是一个标号,它标识了循环的开始位置。当程序执行到 jmp start_of_loop 时,它会跳转回这个标号所标识的位置,实现循环的目的。
总的来说,标号是汇编语言中用于标记和引用代码位置的一种方式,使得程序结构更加清晰,易于理解和维护。
回到offset,举个例子,假设有一个标签为 myLabel,你可以使用 offset 操作符来获取它相对于代码段起始位置的偏移量,就像这样:
mov ax, offset myLabel
在这个例子中,ax 寄存器将被设置为 myLabel 相对于代码段的偏移量。这个偏移量可以在程序中用于计算地址或进行跳转等操作。
总的来说,offset 操作符是用于获取标签或变量在代码段中的位置信息,使程序能够动态地处理内存中的数据和执行跳转等操作。
2.2 nop是什么?
NOP 是汇编语言中的一个指令,它代表 “No Operation”,中文可以理解为“无操作”或“空操作”。这个指令在程序执行时不做任何有意义的操作,实际上就是告诉计算机处理器不要执行任何操作,只是简单地占用一个时钟周期。
为什么会需要这样的指令呢?有时候在编写汇编代码时,为了满足一些特定的要求,比如调整指令的对齐方式或者是占用一些字节的空间,我们可能会需要插入一些没有实际操作的指令。NOP 就是为了满足这种需要而设计的。
在汇编语言中,NOP 可以写作 NOP,也可以写作 NOOP,这两者是等效的。一个典型的使用场景是在调试或优化汇编代码时,通过插入一些 NOP 指令,可以方便地观察程序的行为或者调整指令的布局,而不改变实际的逻辑。
三、jmp指令
3.1 jmp指令的功能
无条件转移,可以只修改IP,也可以同时修改CS和IP
jmp指令要给出两种信息:
转移的目的地址
转移的距离
- 段间转移(远转移): jmp 2000:1000
- 段内短转移: jmp short 标号 ; IP的修改范围为 -128~127,8位的位移
- 段内近转移: jmp near ptr 标号 ; IP的修改范围为 -32768~32767,16位的位移
3.2 jmp指令:依据位移进行转移
引子:常见指令中的立即数均在机器指令中有体现问题:
jmp short 指令中,转移到了哪里?
jmp short 的机器指令中,包含的是跳转到指令的相对位置,而不是转移的目标地址。
下边程序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)指令EB 05执行后,
(IP)=(IP)+05=000AH,CS:IP指向inc ax
3.3 两种段内转移
短转移
短转移:“jmp short 标号”
功能:(IP)=(IP)+8位位移
原理
(1)8位位移=
“标号”处的地址-jmp指令
后的第一个字节的地址;
(2)short指明此处的位移为8位位移;
(3)8位位移的范围为-128~127,用补码
表示;
(4)8位位移由编译程序在编译时算出。
近转移
近转移:指令“jmp near ptr 标号”
功能: (IP)=(IP)+16位位移
原理
(1)16位位移=
“标号”处的地址-jmp指令
后的第一个字节的地址;
(2)near ptr指明此处的位移为16位位移,
进行的是段内近转移;
(3)16位位移的范围为 -32769~32767,
用补码表示;
(4)16位位移由编译程序在编译时算出。
3.4 远转移:jmp far ptr 标号
远转移jmp far ptr 标号
段间转移
far ptr指明了跳转到的目的地址,即包含了标号的段地址CS和偏移地址IP。
近转移jmp near ptr 标号
near ptr 指明了相对于当前IP的转移位移,而不是转移的目的地址。
3.5 转移地址在寄存器中的jmp指令
指令格式:jmp 16位寄存器
功能:IP =(16位寄存器)
举例:
jmp ax
jmp bx
3.6 转移地址在内存中的jmp指令
jmp word ptr 内存单元地址
段内转移
功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址。
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
jmp dword ptr 内存单元地址
段间转移
功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址。
mov ax,0123H mov ds:[0],ax mov word ptr ds:[2],0 jmp dword ptr ds:[0] 执行后, (CS)=0 (IP)=0123H CS:IP指向0000:0123
mov ax,0123H mov [bx],ax mov word ptr [bx+2],0 jmp dword ptr [bx] 执行后, (CS)=0 (IP)=0123H CS:IP指向0000:0123
总结
总体而言,汇编语言中的“转移”是编程中不可或缺的一部分。通过 offset 操作符和 JMP 指令,程序员能够以底层的方式控制程序的执行流程,实现更复杂和灵活的逻辑。这种能力为编程带来了更高的自由度,同时也要求程序员对计算机体系结构有更深入的理解。在深入学习汇编语言的过程中,理解和掌握这些“转移”的机制将成为编程技能中的重要一环。