C++与汇编——段与寄存器

段与寻址

段是在程序中专门定义的一个区域,它是一个包括代码、数据以及堆栈的区域。比如,用ida打开一个exe程序,在反汇编窗口中可以看到程序分成了如下几段:

0x00000-----------
    代码段
0x10000-----------
    数据段
0x20000-----------
    堆栈段
0x26000-----------

段是从小段边界,即能够被16除尽的单元开始的。因此,当一条指令往一个段寄存器装入段地址时,会自动移去最右边的4位。你可以定义任何数据的段,想要访问特定的段,只需要改变适当段寄存器中的地址就可以了。程序的段主要分为三类:代码段、速度段和堆栈段。

  • 代码段包括要执行的机器指令,第一条可执行的指令在该段的起点。
  • 数据段包括程序内部定义的数据、常量和工作区。
  • 堆栈段包括程序需要暂存的任何数据与地址,或者程序调用子程序所用的数据与地址。

段边界

程序访问不同段的数据需要借助不同的寄存器,如下所示

        0x00000-----------

SS寄存器——>      代码段

        0x10000-----------

DS寄存器——>      数据段

        0x20000-----------

CS寄存器——>      堆栈段

        0x26000-----------

由于一个段的地址可以整除16,在此情况下,地址最右侧四位2进制的数字均为0,所以将0存进寄存器是没有必要的。由此段地址038E0是以038E存放于寄存器中,最右边四位被移去。

段偏移值

在一个程序中,段范围内的所有存储单元的寻址都相对于段起始地址,段首地址与段内地址以字节为单位的距离叫做偏移量。在实模式下,偏移量长度最大为两个字节,即0000FFFF。为了访问段内的数据,处理器会将段寄存器中的地址与偏移值组合起来。比如数据段的起点是038E0,DS寄存器内的值就为038E,而要访问数据的偏移量为0032。在访问数据时,处理器会进行如下计算

DS段地址               038E0
偏移量                + 0032
                ———————————————
实际地址               03912

实际访问的地址是03912。注意:程序包含一个或更多的段,段的起点可以是存储器的任何位置,并可排成任何序列,段寄存器的值也是可以改变的。

寄存器

处理器的寄存器用于控制指令执行、存储器寻址和提供算数能力。

段寄存器

段寄存器为一个称为当前段的区段提供寻址。

寻址方式

  • 实模式:实模式下段段寄存器的长度为16位,加上4位的隐藏值,允许寻址的最大范围为20位。
  • 保护模式:保护模式下,最大寻址的长度为24位。此时段寄存器保存的不再是物理地址,而是作为选择器,用来指向存储24位段地址的描述表。保护模式允许处理器实现多任务,这是它能从正在执行的任务转换到另一任务。
  • 80386及后续处理器的寻址模式:实模式与之前相同,保护模式下,处理器使用48位寻址。

CS寄存器

CS寄存器存储了程序代码段的起始地址,这个地址加上指令指针(IP)寄存器中的偏移值,就得到了执行指令的地址

DS寄存器

DS寄存器存储了程序数据段的起始地址,该地址加上偏移值就可以访问数据段中的数据

SS寄存器

SS寄存器存储了程序堆栈段的起始地址,程序可以用该寄存器寻址来临时存放地址和数据。

ES寄存器

ES寄存器指向附加段的基址,附加段在某些类型的数据(如字符串)的操作中用于存储器寻址。在寻址时,ES和DI寄存器相关联。

FS和GS寄存器

处理器备用的附加段寄存器

指针寄存器

指针寄存器有EIP、ESP和EBP,最右边的16为IP、SP和BP

指令指针(EIP)寄存器

IP寄存器包含了要执行的下一条指令的偏移量。IP和CS是相关联的(CS:EIP)。如CS寄存器的值为39B4,IP的值为0514,那么下一条指令的地址为IP+CS=3A054。每执行一条指令,处理器都会改变IP的值,以便执行下一条指令。

堆栈指针(ESP)寄存器

ESP寄存器存储堆栈段的偏移量,与SS寄存器相关联。(SS:ESP)。寻址方式与EIP类似

基址指针(EBP)寄存器

EBP寄存器存储了参数的地址,简化了参数的访问。这些参数是程序通过堆栈传递的数据和地址。EBP与SS相关联(SS:EBP)。EBP可以与DI或SI组合起来,作为用于特殊寻址的基址寄存器。

通用寄存器

通用寄存器是32位的EAX、EBX、ECX和EDX。右边16位称为AX、BX、CX和DX。AX本身由两部分组成:高八位称为AH,低八位是AL。其他寄存器同理,如BH、CL等。

EAX寄存器

EAX是主累加器,用于有关输入/输出和大多数算数运算操作,如乘法、除法和换码指令。此外,某些指令使用EAX可以生成更高效的机器码。

EBX寄存器

EBX是基址寄存器,它是个通用寄存器,可以用作扩展寻址的变址,也可以用于计算。BX还可以和DI或SI组合使用作为专用于寻址的基址寄存器。

ECX寄存器

ECX即计数寄存器,它存储了控制循环的重复次数的值或左、右移位的次数,ECX还可以参与计算。

EDX寄存器

EDX即数据寄存器,用于一些输入/输出操作,当计算大数除法与乘法时DX与AX会组合使用。

变址寄存器

ESI寄存器

ESI是源变址寄存器,用于处理某些数据的寻址

EDI寄存器

EDI是目的变址寄存器,同样用于处理某些数据的寻址

标志寄存器

32位的标志寄存器包含的位用来指明不同的状态

000....1010 ——>总长32位
        |
每一位表示不同的状态,如是否溢出、是否进位等

以下为常用的标志位:

  • OF(溢出):指出算数运算后最左边位的溢出
  • DF(方向):确定传送或比较数据时的左右方向
  • IF(中断):指明是否处理所有外部中断
  • TF(陷阱):指明处理器是否以单步的方式工作,常用于程序的调试
  • SF(符号):包含一次算数结果的符号位
  • ZF(零):指明算数运算或比较操作的结果是否为0
  • AF(辅助进位):包含算数运算中第三位到第四位的进位输出,用于专门的算术运算
  • PF(奇偶):指明操作产生的结果位中’1’的数量,偶为0,奇为1
  • CF(进位):包含一个算术运算操作后来自最左边位的进位,还包含位移或循环操作最后一位的内容。

对于比较和算术运算操作而言,关系最大的标志位为OF、SF、ZF和CF。