6.3 将数据,代码,栈放入不同的段

发布时间 2023-07-09 11:53:48作者: 三年、

6.3 将数据,代码,栈放入不同的段

  1. 注意, 当数据,代码,栈需要的空间超过64kb时(偏移地址的范围),就不能放在一个段内,这是8086模式的限制

  2. 示例程序如下:

    assume cs:code, ds:data, ss:stack
    
    data segment
          dw    0123H, 0456H, 0789H, 0abcH, 0defH, 0fedH, 0cbaH, 0987H
    data ends
    
    stack segment
          dw    0, 0, 0, 0, 0, 0, 0, 0
    stack ends     
    
    code segment
    
    start:      mov ax, stack
                 mov ss, ax
                 mov sp, 16
                 mov ax, data
                 mov ds, ax
                 push ds:[0]
                 push ds:[2]
                 pop ds:[2]
                 pop ds:[0]
                 
                 mov ax, 4c00h
                 int 21h
    code ends
    end start
    
    • 程序中“data”段中的数据“0abch”的地址就是:data:6。

      我们要将它送入bx中,就要用如下的代码:

       mov ax,data
       mov ds,ax
       mov bx,ds:[6]
      

      我们不能用下面的指令:

       mov ds,data     
       mov ax,ds:[6]
      

      其中指令“mov ds,data” 是错误的,因为8086CPU不允许将一个数值直接送入段寄存器中。

      当我看到下面这段代码

       mov ax,data
       mov ds,ax
       mov bx,ds:[6]
      

      我有一个疑问,就是assume cs:code, ds:data, ss:stack 不是已经将data和ds绑定了吗,何必再一次赋值呢?(可参考(73条消息) 汇编语言——assume的作用_汇编assume_手写的从前66的博客-CSDN博客

      • 首先要明白的是 assume 是伪代码,无法翻译成机器语言,只有由编译器运行。因此 data 是无法赋值给 ds 的,因为不存在这样一条命令。

      • 换句话说,编写程序,是写给编译软件的。由编译软件,编译成机器码,再去控制CPU。但是,编译软件,对assume语句,并不生成机器码。所以,必须有mov ax,data,mov ds,ax,CPU才能受控。assume语句,是伪指令,仅仅是写给编译软件的。编译软件,并不把它生成机器码。

      • 个人理解,可以把 data 看作 java 中的运行时才确定的变量,只是一种声明的段名,实际运行时才确定真正的值,其含义只是一种规范,给程序员看以知道各个段的含义。

      • assume对除了CS以外的其它段寄存器,仅仅只是关联了段名,以便在访问段内变量时程序可以知道用哪个段寄存器,并没有在程序加载时将段地址装入段寄存器。所以,将段地址装入段寄存器的工作,必须由用户在程序中自己编写代码,并在程序开始运行时执行代码完成装入工作。
        仅仅对CS段寄存器,会在关联段名的同时,在程序加载时自动将段地址装入段寄存器。

      • 作用:用于标识默认段前缀

        解释:assume 并不能改变ds等段寄存器的值,但他能改变编译器产生的汇编代码。比如:

        assume ss:stack
        
        stack segment
        
        x :db 0
        
        stack ends
        
        

        如果程序需要mov ax,[x],那么程序如何定位[x]呢?我们知道x只是一个偏移地址0,所以此时assume就相当于告诉编译器stack段的所有标号都与ss相关联,所以此时[x]就相当于ss:[0]。如果我们直接将这句改为mov ax,ss:[0],那么前面不加assume也是可以的。这也是为什么[0]被编译器强制理解为立即数,而[标号]却被理解为标号里的内容的原因,因为标号必须与段assume,否则会报错cannot address with segment register。而[0]无默认段,就只能被认为为立即数了。