汇编语言(七)
第六章:包含多个段的程序
我们之前说0:200-0:2ff是安全空间,但容量其实只有256字节。如果我们的需要超出这个大小,还需要向操作系统申请。在操作系统允许的情况下,程序可以取得任意容量的空间。
我们通过在源程序中定义段来获取内存空间。我们定义不同的段来存放不同类型的数据,比如代码段,数据段,栈段。
比如此类问题,我们在上一章已经知道,可以通过循环进行累加。但是,如何将这初始的数据存储在一组连续的内存单元中呢?
应该让系统为我们分配这样一段连续内存空间,我们用指令将其送入连续内存空间。比如如下程序
1 | assume cs:code |
在这里dw代表定义字型数据也就是define words,显然这里定义了8个字型数据总共也就是16个字节。
但是这8个数据存放在哪里呢
因为我们初始定义的是代码段code,所以可以从cs中得到其段地址,并且因为dw定义的数据在代码段的最开始,所以偏移地址为0。这4个数据就在代码段的便宜0,2,4,6处。随着累加依次读取完毕。
我们可以调试一下上述程序
开始调试,先查看当前cs指向的地址。可以看到我们看不懂076A处的指令,因为开始的数据,指令左边显示的2312,不应该翻译成指令,而是我们定义的字型数据!所以我们当然看不懂指令。于是我们向下查看8个字节。
用此命令,找出前八个字节如图所示,正好为我们定义的字型数据!
但是问题来了,我们没法用debug直接执行啊,前面都是数据啊,所以我们应该定义一下程序入口,让程序执行的时候直接从入口开始。用start即可!
既然有start,就可以再来分析一波end了,end其实不只通知编译器程序结束,还能通知入口在什么地方,也就是start处。
这个入口的便宜地址会被添加在可执行文件的描述信息中。
6.2代码段中使用栈
我们来看这样的问题
所以要先让系统分配一段可当作栈的内存空间。可以通过刚才,在程序中定义数据的方式,来获取一段空间,然后把这段空间当作栈来使用!
来看程序
定义了一段空的栈空间,16个字节大小,然后我们先入栈,把8个字节的数据入栈,然后再重置bx和cx之后出栈。
对于本程序,我们将cs:10-cs:2F当作栈空间来使用。所以要设置好栈底,即ss:sp指向栈底cs:30。
下面我们来看一个练习
我们来做一个分析:
显然先定义了数据,然后定义了数据段ds,也就是要用ds中的内容改写我们程序中的内容。
所以我们要加入
1 | mov cs:[bx], ax |
这样即改变了程序中定义的8个字型数据。
再来看下一解,我们尝试用栈去修改此内容。
可以看到我们定义了10个空白空间用作栈空间。
当然,要定义好栈底,我们把10-23当作栈空间来使用,显然栈底指向24(图中标注有误)
我们既然想让数据段ds中的数据来改变现有程序中的数据,就可以让ds中数据先行入栈
1 | push [bx] |
如图中也有,并且让数据出栈道cs:[bx]即可!
6.3将数据,代码,栈放入不同的段
我们刚才把数据,代码都放入了一个段,其实非常混乱,我们可以定义多个段来分别存放代码,数据和栈!
我们下面举个例子,定义多个段,来实现上面程序实现的数据改写功能!
1 | assume cs:code,ds:data,ss:stack |
段名就相当于一个标号,代表了段地址,所以
1 | mov ax,data表示将名称为data的段的地址送入ax |
比如我们将data中第六偏移地址的数据送入bx,即
1 | mov ax,data |
对于段的命名,完全是看个人意愿的。
下面是练习时间
我们来分析一下程序要做什么
程序在最后定义了数据段和栈段,最开始为代码段。程序实现不过是把数据段入栈,然后在按顺序出栈,注意出栈顺序,先进后出,后进先出!
我们看这一问,非常精彩。我们先查看cx,cx中存放了所有机器码占用空间,比如(0444)也就是68个字节,我们用68减掉栈空间和数据空间的大小,也就是68-16-16,这里问什么减16呢,因为有这样一条规定:不满16的按16处理!
所以得到code段占用空间为3个段也就是48字节!所以,当start处开始时,先到code段,也就是经过48字节所以data段地址为X+3,stack段地址为X+4。
本章内容结束!