找回密码
 register

QQ登录

只需一步,快速开始

查看: 30|回复: 0

[汇编语言] [零基础入门学习]·30·包含多个段的程序·在代码段中使用数据

[复制链接]

[汇编语言] [零基础入门学习]·30·包含多个段的程序·在代码段中使用数据

[复制链接]
  • 打卡等级:热心大叔
  • 打卡总天数:91
  • 打卡月天数:14
  • 打卡总奖励:91
  • 最近打卡:2025-01-15 02:59:34
Waylee

主题

0

回帖

1万

积分

仙帝

积分
11890
Waylee 2025-1-6 14:25 | 显示全部楼层 |阅读模式 | Google Chrome | Windows 10

马上注册,查看网站隐藏内容!!

您需要 登录 才可以下载或查看,没有账号?register

×



第6章 包含多个段的程序

前面的程序中,只有一个代码段。现在有一个问题是,如果程序需要用其他空间来存储数据,使用哪里呢?第5章中,我们讲到要使用一段安全的空间。可哪里安全呢?第5章中,我们说0:200~0:2FF是相对安全的,可这段空间的容量只有256字节,如果我们需要的空间超过256个字节怎么办呢?

在操作系统的环境中,合法地通过操作系统取得的空间都是安全的,因为操作系统不会让一个程序所用的空间和其他程序以及系统自己的空间相冲突。在操作系统允许的情况下,程序可以取得任意容量的空间。

程序取得空间的方法有两种,一是在加载程序的时候为程序分配,再就是程序在执行的过程中向系统申请。在我们的课程中,不讨论第二种方法。

加载程序的时候为程序分配空间,我们在前面已经有所体验,比如我们的程序在加载的时候,取得了代码段中的代码和存储空间。

我们若要一个程序在被加载的时候取得所需的空间,则必须要在源程序中做出说明。我们通过在源程序中定义段来进行内存空间的获取。

上面是从内存空间获取的角度上,谈定义段的问题。我们再从程序规划的角度来谈一下定义段的问题。大多数有用的程序,都要处理数据,使用栈空间,当然也都必须有指令,为了程序设计上的清晰和方便,我们一般也都定义不同的段来存放它们。

对于使用多个段的问题,我们先简单说到这里,下面将以这样的顺序来深入讨论多个段的问题:
(1) 在一个段中存放数据、代码、栈,我们先来体验一下不使用多个段的情况;
(2) 将数据、代码,栈放入不同的段中。

6.1  在代码段中使用数据

考虑这样一个问题,编程计算以下8个数据的和,结果存在ax寄存器中:
0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
在前面的课程中,我们都是累加某些内存单元中的数据,并不关心数据本身。可现在要累加的就是已经给定了数值的数据。我们可以将它们一个一个的加到ax寄存器中,但是,我们希望可以用循环的方法来进行累加,所以在累加前,要将这些数据存储在一组地址连续的内存单元中。如何将这些数据存储在一组地址连续的内存单元中呢?我们可以用指令一个一个地将它们送入地址连续的内存单元中,可是这样又有一个问题,到哪里去找这段内存空间呢?

从规范的角度来讲,我们是不能自己随便决定哪段空间可以使用的,应该让系统来为我们分配。我们可以在程序中,定义我们希望处理的程序,这些数据就会被编译、连接程序作为程序的一部分写到可执行文件中。当可执行文件中的程序被加载入内存时,这些数据也同时被加载入内存中。与此同时,我们要处理的数据也就自然而然地获得了存储空间。

具体的做法看下面的程序。

程序6.1

assume cs:code

code segment
    dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

    mov bx,0
    mov ax,0

    mov cx,8
s:  add,ax,cs:[bx]
    add bx,2
    loop s

    mov ax,4c00h
    int 21h

code ends

end

解释一下,程序第一行中的“dw”的含义是定义字型数据。dw即“define word”。在这里,使用dw定义了8个字型数据(数据之间以逗号分隔),它们所占的内存空间的大小位16个字节。

程序中的指令就要对这8个数据进行累加,可这8个数据在哪里呢?由于它们在代码段中,程序在运行的时候CS中存放代码段的段地址,所以可以从CS中得到它们的段地址。它们的偏移地址是多少呢?因为用dw定义的数据处于代码段的最开始,所以偏移地址为0,这8个数据就在代码段的偏移0、2、4、6、8、10、A、C、E处。程序运行时,它们的地址就是CS:0、CS:2、CS:4、CS:6、CS:8、CS:A、CS:C、CS:E。

程序中,用bx存放加2递增的偏移地址,用循环来进行累加。在循环开始前,设置(bx)=0,cs:bx指向第一个数据所在的字单元。每次循环中(bx)=(bx)+2,cs:bx指向下一个数据所在的字单元。

将程序6.1编译、连接为可执行文件p61.exe,先不要运行,用Debug加载查看一下,情况如图6.1所示。

61.webp

图6.1中,通过“DS=0B2D”,可知道程序从0B2D:0000开始存放。用u命令从0B3D:0000查看程序,却看到了一些让人看不懂的指令。

为什么没有看到程序中的指令呢?实际上用u命令从0B3D:0000查看到的也是程序中的内容,只不过不是源程序中的汇编指令所对应的机器码,而是源程序中,在汇编指令前面,用dw定义的数据。实际上,在程序中,有一段代码段,在代码段中,前面的16个字节是用“dw”定义的数据,从第16个字节开始才是汇编指令所对应的机器码。

可以用d命令更清楚地查看一下程序中前16字节的内容,如图6.2所示。

6.2.webp

可以从0B3D:0010查看程序中要执行的机器指令,如图6.3所示。

6.3.webp

从图6.2和6.3中,我们可以看到程序加载到内存中后,所占内存空间的前16个单元存放在源程序中用“dw”定义的数据,后面的单元存放源程序中汇编指令所对应的机器指令。

怎样执行程序程序中的指令呢?用Debug加载后,可以用IP设置为10h,从而使CS:IP指向程序中的第一条指令。然后再用t命令、p命令,或者是g命令执行。

可这样一来,我们就必须用Debug来执行程序。程序6.1编译、连接成可执行文件后,在系统中直接运行可能会出现问题,因为程序的入口处不是我们所希望执行的指令。如何让这个程序在编译、连接后可以在系统中直接运行呢?我们可以在源程序中指明程序的入口所在,具体做法如下。

程序6.2

assume cs:code

code segment
    dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

start:  mov bx,0
        mov ax,0

        mov cx,8
s:      add,ax,cs:[bx]
        add bx,2
        loop s

        mov ax,4c00h
        int 21h

code ends

end start

注意在程序6.2中加入的新内容,在程序的第一条指令的前面加上了一个标号start,而这个标号在伪指令end的后面出现。这里,我们要再次探讨end的作用。end除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方。在程序6.2中我们用end指令指明了程序的入口在编号start处,也就是说,“mov bx,0”是程序的第一条指令。

在前面的课程中(参见4.8节),我们已经知道在单任务系统中,可执行文件中的程序执行过程如下。

  1. 由其他程序(Debug、command或其他程序)将可执行文件中的程序加载入内存;
  2. 设置CS:IP指向程序的第一条要执行的指令(即程序的入口),从而使程序得以运行;
  3. 程序运行结束后,返回到加载者。

现在的问题是,根据什么设置CPU的CS:IP指向程序的第一条要执行的指令?也就是说,如何知道哪一条指令是程序的第一条要执行的指令?这一点,是由可执行文件中的描述信息指令的。我们知道可执行文件由描述信息和程序组成,程序来自于源程序中的汇编指令和定义的数据;描述信息则主要是编译、连接程序对源程序中相关伪指令进行处理所得到的信息。我们在程序6.2中,用伪指令cmd描述了程序的结束和程序的入口。在编译、连接后,由“end start”指明了程序入口,被转化为一个入口地址,存储在可执行文件的描述信息中。在程序6.2生成的可执行文件中,这个入口地址的偏移地址部分为:10H。当程序被加载入内存之后,加载者从程序的可执行文件的描述信息中读到程序的入口地址,设置CS:IP。这样CPU就从我们希望的地址处开始执行。

归根结底,我们若要CPU从何处开始执行,只要在程序中用“end 标号”指令就可以了。

有了这种办法,就可以这样来安排程序的架构:

assume cs:code

code segment
        ·
        ·
        ·
        ·
        数据
        ·
        ·
        ·
        ·
start:
        ·
        ·
        ·
        ·
        代码
        ·
        ·
        ·
        ·
code ends
end start
您需要登录后才可以回帖 登录 | register

本版积分规则

雪舞知识库 | 浙ICP备15015590号-1 | 萌ICP备20232229号|浙公网安备33048102000118号 |天天打卡

GMT+8, 2025-1-15 13:42 , Processed in 0.109215 second(s), 8 queries , Redis On.

Powered by XueWu Licensed

Copyright © Tencent Cloud.

快速回复 返回顶部 返回列表