首先,assume是伪指令,是为编译器服务的;
assume的作用仅仅是告诉编译器,我碰到一个标号,要计算它的物理地址的时候,从哪一个段寄存器里面取出段值,至于这个段寄存器的值对不对,那它就不管了,这是程序员的事情,反正它只管根据 assume 里面的设定来用段寄存器,所以,对于程序员来说,不仅要用 assume 告诉编译器计算物理地址的时候要从哪一个段寄存器取值,而且要在指令中明确的把对应段的段值送到设定好的段寄存器中。
还是先来个例子(为了突出重点,例子都是很简单,甚至仅为测试而写,没有实际意义)
DATA SEGMENT ;数据段
MESS DB "HELLO",0DH,0AH,'$'
DATA ENDS
;
CODE SEGMENT ;代码段
ASSUME CS:CODE,DS:DATA
START: MOV AX,DATA
MOV DS,AX
<font color="#0000dd">
MOV DX,OFFSET MESS
</font>
MOV AH,9 ;显示信息HELLO
INT 21H
MOV AH,4CH
INT 21H ;返回DOS
CODE ENDS
END START
在这个程序中,红色指令对应的是取得MESS的偏移地址,当我们对于MESS进行访问时候,汇编程序识别呢?我看可以这么理解哈,首先看到MESS的时候,汇编程序察觉这个是在DATA段中定义的变量,但是要访问它的时候,必须知道它的确切地址才行,所以在DATA段中,必须知道DATA的段地址,这个时候程序开始的前两条语句就已经给DS赋予了值,但是我们如何得知DS和DATA的关系呢?这个时候就是assume的作用了,它就是告诉汇编程序,用指定的段寄存器寻址相应的逻辑段,建立段寄存器与段的默认关系。所以程序的开始用的是两个assume指令使代码段与数据段和指定的寄存器关联起来,程序的段地址知道了,偏移地址就是汇编程序地址计数器在进行汇编的时候自动算出来的,这个不用我们担心!
另外在dos装入EXE程序的时候,DS和ES被初始化为PSP(程序段前缀)的段地址,而不是用本身的数据段和附加数据段,所以源程序中必须重新初始化DS和ES。CS:IP指向源程序的代码段,cs必须被关联到指定的段,否则程序不能运行(代码段必须用ASSUME CS:CODE指明,否则编译器不知道代码从何处开始执行,编译不通过)。SS:SP指向程序的堆栈段,如果程序未设堆栈,则SS为PSP的段地址加上256个字节,SP为00h。
上面说的可能还是不太清楚,写2个例子在下面看哈或许更明白些吧
DATA SEGMENT ;数据段
MESS DB "HELLO",0DH,0AH,'$'
DATA ENDS ;
CODE SEGMENT ;代码段
<font color="#0000dd">
ASSUME CS:CODE,ES:DATA ;用ES关联,一样的效果
</font>
; ASSUME CS:CODE,DS:DATA
START: MOV AX,DATA
MOV ES,AX
mov al,mess + 1
or al,20h ;大写变小写
mov mess+1,al
MOV AX,ES
MOV DS,AX
MOV DX,OFFSET MESS
MOV AH,9 ;显示信息HELLO
INT 21H
MOV AH,4CH
INT 21H ;返回DOS
CODE ENDS
END START
结果输出的是HeLLO
我们可以把红色代码换成ASSUME CS:CODE,DS:DATA,输出结果是HELLO,即没有变化。我们可以看下反汇编的代码就一切明白了。
没有改动的代码,可以看到访问变量mess的时候,自动加上了es段寄存器,这个就是assume的作用。如果改成ASSUME CS:CODE,DS:DATA,那么访问mess的话,则自动关联到ds寄存器,但是我们的程序中ds的值没有赋值,即ds的值还是原来程序段前缀的段地址,所以我们写的大小写转换不是在操作我们的数据,而是PSP中的某个数据。
相信说到这了,大家应该有一点稍微清晰的认识吧!