汇编学习教程:好好搞懂段

前言

什么是段?初看一眼可能会很不解,其实段的概念在之前的博文中有所提及,只不过那时候并没有具体详细的讲述。细心的小伙伴可能会记得,之前博文中我们讲述了CPU眼中的内存,是一条以下标0开始的“直线”,在这条直线上,塞着各个电子器件的内存单元地址,比如我们规定:8000H~9FFFH是我们电脑显存地址范围,向这段内存中写入数据(ASCALL码),屏幕上将会显示出来。那么,这个8000H~9FFFH的范围,我们就可以称之为一个“段”,你可以乐意的称呼它为“显存段”。

具体来说,段是人为对内存上的一段区域的划分,CPU中是没有段的概念,段的存在只是为了帮助人们更好的审视和理解内存,从而简化了开发难度。

例如,我们可以认为10000H~100FFH的内存空间组成了一个段,这个段起始地址为10000H(描述为1000:0),那么段地址就为1000H,大小为100H。还记得之前博文中讲述的寻址方式么?8086CPU中寻址方式为:基地址✖16➕偏移地址。这里我们可以认为,基地址就是段地址(重要),段的起始地址10000H,就可以表示为段地址(1000H)✖16➕偏移地址(0H)。

还是上面的例子,10000H~100FFH这个段中,你还可以再分好几个段,比如你可以认为10000H~1007FH的内存空间是另外一个段,10080H~100FFH的内存空间也是一个段。那么对于10000H~1007FH段来说,段起始地址为10000H,段地址为1000H,长度80H;对于10080H~100FFH段来说,段起始地址为10080H,段地址为1008H,长度20H。

从上面的距离我们可以看出,段的定义是由我们程序员来定义的,通过对内存空间划分不同的区域,来简化开发难度,增强程序理解。

段寄存器

相信你此时已经完全理解了段的定义,那么下面我们就开始认识段寄存器。

上篇博文中,我们讲述了CPU中的通用寄存器:AX,BX,CX,DX。CPU中当然不止这四个寄存器,还有一类寄存器也是相当的重要,那就是段寄存器。

首先我们先来想一下,一个程序会需要到什么数据?

1:最重要最关键的,那就是代码

2:必不可少的各种变量,包括在程序起始定义好的变量和方法中写的临时变量

当然,一个汇编程序也是少不了上述两大块。上面我们已经说过CPU眼中的内存,也就是说,当我们的汇编程序被加载进内存开始执行的时候,实际上我们的代码和变量都是放在一起的,在CPU来看都是一堆二进制数字,并没有哪块是代码哪块是变量的区分。

结合一下我们今天学习的段,为了避免代码和变量在内存中的混乱,所以就需要在内存空间划出一段区域来规定这段内存中的数据就是代码,另外一段的区域数据就是变量。段已经划分出来,那么段地址肯定要找个地方放起来以便访问,所以人们便在CPU中设计了段寄存器来存放这些段地址。

在8086CPU中,共有四个段寄存器:

1:CS,Code segment,它指明了指令段(代码)所在内存地址

2:DS,Data segment,它指明了数据段(变量)所在内存地址

3:SS,Stack segment,它指明了栈段所在的内存地址

4:ES,Empty segment,这个段是当作预留段,当出现段寄存器不够用的情况下,可以使用它来作为补充

CS和IP

如果是熟悉脱壳和破解的小伙伴,估计对这两个家伙就是非常的熟悉了,因为它们两个决定程序的走向。

CS是代码段寄存器,段寄存器实际上和通用寄存器一样,也是一个16位寄存器。与通过寄存器不同的是,通用寄存器一般存储数值,而段寄存器中则存放的是段地址。

以CS为例,CS寄存器中存放的就是代码段的段地址。上面我们说过段地址实际上就是基地址,那么势必需要一个偏移地址才能得到最终的目的地址,才能拿到数据。

对于CPU而言,如果想要得到代码数据,那么它就要通过寻址找到代码存放的内存空间(即代码段),从那里才能取到代码数据。现在代码段的段地址已经有了,还需要一个偏移地址,这个偏移地址就在IP中存放。

IP是指令指针寄存器,里面存放的是代码段的偏移地址。在8086PC机中,任意时刻CPU将CS:IP指向的数据当作指令进行执行。也就是说,CS:IP指向的内容就是代码

8086CPU程序运行的过程为:

  1. 通过地址加法运算器将CS和IP两个寄存器中的地址合成目的地址,通过地址总线访问到该地址
  2. 通过指令总线下发读取的指令,存储器便将该地址对应下的二进制数据通过数据总线送入CPU中
  3. IP中的偏移地址会自动加上该指令数据的长度,此时IP中数据变成下条指令所在的偏移地址
  4. CPU开始执行

执行完毕后,CPU会重复1步骤,取到下条指令进行执行。

注意点

这里可能会有所混淆,之前的博文中我们有讲述CPU三大总线,指令总线用来传输指令,数据总线用来传输数据,那为什么在上述中,我们的程序代码(指令)却是通过数据总线传入CPU中而不是通过指令总线呢?

如果你有上述疑问说明之前的三大总线的作用你没有完全理解,三大总线是CPU与外部电子器件相联系的通道,CPU与外部电子器件交互是电信号,为了区分电信号是地址还是指令还是数据,所以人们在进行了总线区分,每种总线传输的电信号分别对应不同的信息。

指令总线则是传输CPU对外部电子器件下发的读写指令(电信号),注意,这个指令是CPU下发给外部电子器件的,通常就是两种指令,读取或者写入。在上述CPU执行代码过程,CPU就通过指令总线给存储器下发读取指令。

我们的程序要想运行,首先它要先被加载进内存中,此时程序在内存中的状态就是一堆二进制数据,数据当然要通过数据总线才能进入CPU中。由于送进来的数据它的地址是CS:IP指向的,所以CPU就会把这段数据当作指令进行执行。

跳转指令

平常我们在做开发的时候,代码中避免不了会出现各种判断:if、else、switch;还会有各种循环:for、while。这些操作都改变了程序的运行方向,符合特定的判断条件,程序将会执行判断后的代码语句。

当然,汇编开发中也会避免不了判断和循环,假设符合了特定的判断套件,那么该如何改变程序的运行方向?我们把目光转向CS:IP,我们知道CPU会把CS:IP指向的数据当作程序代码来执行,如果我们想改变程序运行方向,那么只需要改变CS和IP值即可,CPU就会执行新地址上的代码,这样程序运行方向不就改变了嘛!

好,该怎么修改CS和IP值呢?

你可能会相到上篇博文中的MOV指令,CS和IP也是寄存器呀,直接MOV指令给他俩赋值不就行了么!答案是肯定不能,因为MOV指令是无法操作CS和IP的。

不要着急,CPU当然提供了其他的指令来修改。能够改变CS和IP值的指令,统统被成为转移指令。转移指令有非常多,多种多样,这里我们就先学习最简单的一个转移指令:JMP

JMP指令格式为:JMP 段地址:偏移地址

例如:jmp 2AE3:3,执行完毕后,CS值为2AE3H,IP值为0003H,CPU将执行2AE33H处的代码。

jmp 3:0B16,执行完成后,CS值为0003H,IP值为0B16H,CPU将执行00B46H处的代码。

jmp也可以配合通用寄存器使用,格式为:JMP 寄存器名,此时仅修改IP中的值。

例如:jmp AX,执行完成后,IP中的值将被修改为AX中的值。

代码段

我们写好了一份汇编程序,比如下面代码:

mov ax,0
add ax,0123H
mov bx,ax
jmp bx

共四行语句,总长度10个字节。10个字节是指上述汇编代码被编译器转为机器码的长度。

现在我们定义一段空间,123B0H~123B9H,这段内存空间为代码段,那么该代码段段地址为:1000H,偏移地址为:23B0H,起始地址表示为:1000:23B0。

我们将上述代码放入已经定义好的代码段空间中,那么如何该如何执行我们的代码?注意代码段的定义和划分都是我们人为的,CPU当然不明白这一安排,在它看来123B0H~123B9H内存空间中都是一堆的二进制数字罢了,它只会将CS:IP指向的空间数据当作指令来执行。所以如何让CPU去执行我们的代码,答案就是修改CS:IP,将CS:IP的指向改成我们定义的代码段第一条指令即可。

所以,需要将CS值改为1000H,IP值改为23B0H,这样CPU就可以愉快的执行我们的代码啦。

再提一句

关于CPU寻址,这里再提一句。

同一个目的地址,可以使用不同的基地址和偏移地址去表达。 

举一个很简单的例子就明白了。比如113这个数字,我们可以表达成:10×10+13,我们当然也可以表达成:11×10+3。这两种表达方式不相同,但是都是表达的同一个数字:113。

回到我们的寻址,例如上面我们定义的代码段,起始地址为:123B0H,我们可以使用:1000H×16+23B0H,也可以使用:1230H×16+B0H,这两个基地址和偏移地址都不相同,但是它们都可以用来寻相同的地址:123B0H。

本篇结束语

本篇我们主要讲述了段的定义,提到了8086CPU中的段寄存器。重点讲述了CS和IP两个寄存器,它们两个的指向标示了CPU执行的代码,介绍了一个最简单的跳转指令JMP,相信你已经都学会了。

在下篇博文中,我们将会提及DS数据段寄存器,以及汇编开发环境的部署。

感谢围观,转发分享请标明出处,谢谢!

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值