如下面一段代码:
data segment
value db ?
data ends
code segment
start:
assume code:cs data:ds ;(1)将段寄存器cs和ds分别和段名code和data联系起来
mov ax,data
mov ds,ax ;(2)
mov ax,value ;(3)
code ends
end start
请注意,这个assume是个伪指令,是编译时由编译器执行的,旨在告诉编译器段名和段寄存器的联系,并没有真的让段寄存器指向对应的段。因此,需要手动进行这样的指向,即2处的代码
那么为什么还需要这样的assume呢?不是只有手动指向不就行了吗?
以下为个人理解----
变量具有三个属性:段值SEG、偏移地址EA、类型TYPE
要使用变量当操作数,必须得到这个变量的属性。变量名本身代表了EA,而TYPE由另一操作数或操作码指定,那么SEG呢?SEG即段名,但汇编里并没有定义“自定义段名:EA”的寻址方式,只定义了“REG:EA”,所以由assume说明段名和哪个段寄存器联系,从而进行汇编时的解释。
例如编译器在汇编时会把mov ax,value解释为mov ax,REG:EA 因此我们可以看到assume的作用,如果没有这个assume的话(比如masm里就可以省略数据段的assume),编译器会默认REG为ds。如果assume中说明data段与es联系起来的话,那么mov ax,value会被解释为
mov ax,es:ES 当然,这个es代表的段值,得由你去实际指定,编译器只是根据assume来进行形式上的解释。
------解决方案--------------------
assume code:cs data:ds ;(1)将段寄存器cs和ds分别和段名code和data联系起来;
这写错啦,应该是 assume cs:code,ds:data
我觉得assume就是一个假设连接的做用
------解决方案--------------------
assume ds:data 这样的语句没有所想像的那么复杂,它的作用就是告诉编译器,接下来是 ds 指向 data 段,这样编译器在遇到访问这个段里的内容时就不会再加上额外的段前缀指令了。这好像是理所当然的,但其实不然,尤其是有多个数据段的情况下,究竟现在是哪个段寄存器指向哪个数据段,是非常重要的;比如 assume ds:data1, es:data2 这样的话,访问 data1 段里的内容就不会有 ds: 这样的不必要的段前缀指令,如果是访问 data2 中的内容,就会被编译器自动加上 es: 这样的必须的段前缀指令,否则按通常的 ds: 的设置来进行访问的话,最后完整地址肯定就是错误的了。之所以 assume ds: 类语句和 mov ds, ax 这样的都需要,是因为不能要求编译器去分析你的指令的功能,进而能判定出当时是哪个段寄存器指向哪个段。
------解决方案--------------------
正如你所说的,assume还有其他用法,比如将寄存器变量与一个struct关联:
XYZ struct
nm dd 256 dup(?)
id dd ?
XYZ ends
assume eax:ptr XYZ
mov edx,[eax].id
------解决方案--------------------
assume 告诉编译器把寄存器预先装入某些值,就是程序在调入内存后,你的代码运行前,环境给你初始化assume的寄存器,然后再跑你的代码。