1.前面我们写的程序中,只有一个代码段,我们先来在代码段中使用数据,看看和单独一个数据段存放数据有什么差别。
考虑这样一个问题,编程计算以下8个数据的和,结果存放在ax寄存器中:
0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
我们希望循环进行累加,所以要将数据存放在一个连续内存当中,如何将这些数据存储在一组地址连续的内存单元中呢?我们可以用指令一个一个将他们送入地址连续的内存单元,可是这样又存在一个问题,到哪里去找这段内存空间?
从规范的角度讲,我们是不能自己随便决定哪段空间可以使用,应该让系统来为我们分配。我们可以在程序中,定义我们希望处理的数据,这些数据就会被编译,连接程序作为程序的一部分写到可执行文件中。当可执行文件被加载入内存时,这些数据也就同时被载入内存中。与此同时,我们要处理的数据也就自然而然的获得了存储空间。
程序如下:
assumme 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、A、C、E处。
根据上面的分析,我们就会发现一个问题,代码段的开始部分并不是我们想要执行的代码,而是定义的8个数据,所以直接执行会产生问题,如何在这个程序编译之后再系统中直接运行呢?我们可以通过标号指定代码段的入口点
程序如下:
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
注意我们加入的新内容,我们在程序的第一条指令的前面加上了一个标号start,而这个标号在伪指令end的后面出现。这里,我们要再次讨论end的作用。end除了通知编译器程序结束之外,还可以通知编译器程序的入口地址在什么地方。在上述程序中我们用end指令指明了程序的入口在标号start处。
现在的问题是,根据什么设置CPU的CS:IP指向程序的第一条要执行的指令?也就是说,如何知道那一条指令是程序第一条要执行的指令?这一点,是由可执行文件中的描述信息指明的(Linux下面目标文件是ELF格式,在ELF Header中存有入口地址)。我们知道可执行文件是由描述信息和程序组成,程序来自于源程序中的汇编指令和定义的数据。我们上面的程序中,用伪指令end描述了程序的结束和程序的入口,在编译连接后,由end
start指明程序的入口,被转化为一个入口地址,存储在可执行文件的描述信息中。
归根结底,我们若要CPU从何处开始执行程序,只要在源程序中用”end 标号“指明就可以了。
代码段中存放数据,码迷,mamicode.com