汇编assume

引用自浙江大学白洪欢老师的解释。

assume只是对编译器编译程序起作用,并不能对段寄存器进行实际的赋值。
assume的目的是为了在编译时确定变量的段地址。
比如你在data段里定义了一个变量叫abc,然后你在
code段里引用了此变量,比如:
mov ah, [abc] 或者 mov ah, abc
那么在编译的时候,编译器首先计算出abc的偏移地址假定为0,
然后还要确定abc的段地址data与哪个段寄存器对应。如果你
assume ds:data,那么,编译出来的结果是:
mov ah, ds:[0000]
如果你assume es:data,那么编译出来的结果是:
mov ah, es:[0000]
如果你assume ds:data, es:data,这里就有个优先的问题,
ds的优先级高于es,所以编译出来的结果仍旧是:
mov ah, ds:[0000]

 

assume不对段寄存器进行赋值的,只是帮助编译器确定变量的段地址。假定变量abc的偏移地址是0,段地址是data,那么在编译
  mov ah, [abc]
这句话时,变量名abc肯定要被替换成实际的段地址及偏移地址
  mov ah, data:[0000]
但是,我们知道,段地址data本身不能用来表示指令中的段地址,必须用一个段寄存器来代替才行。所以,此时编译器需要选择ds、es、ss、cs中
的其中一个来代替data。它的选择决定于你是怎么assume的,而完全不管程序执行的时候这些段寄存器的值是否等于data(事实上编译的时候程序还没有
运行,编译器怎么可能知道4个段寄存器的值?)。

因此,把
  mov ah, [abc]
编译成
  mov ah, ds:[0000]
是因为你前面assume ds:data。如果你没有assume的话,编译会出错,因为变量所在段虽然是data,但是它不知道该用哪个段寄存器来代替data。这是出错

的主要原因。注意这里编译出来的
mov ah, ds:[0000]
中,ds这个段寄存器的值本身不会自动
被赋值为data的。

========================================以下为个人补充============================================================

但是如果你在使用[abc]时,都手动指定ds:[abc],并且你在程序的一开始就把data的地址赋值给ds的话,也是可以的。例如:

data segment
    char db 'a'
data ends
code segment
assume cs:code
main:
   mov ax, data
   mov ds, ax
   mov ah, ds:[char]
   mov ah, 4ch
   int 21h
code ends
end main

### 汇编语言中的 `assume` 指令 #### 作用与功能 `assume` 指令用于告诉汇编程序关于段寄存器的内容假设。这有助于链接器理解哪些段寄存器对应于特定的内存区域,从而正确处理代码和数据访问[^1]。 #### 使用场景 当编写涉及多个段(如代码段、数据段等)的程序时,使用 `assume` 可以简化编程工作并提高可读性。通过指定某个段寄存器关联到具体的段名,在后续代码中可以直接引用该段内的变量或标签而无需每次都显式加载相应的段地址。 #### 基本语法结构 ```assembly ASSUME 寄存器列表 : 段名称 [, ...] ``` 其中,“寄存器列表”可以是一个单独的段寄存器(如 CS, DS, ES 等),也可以是由逗号分隔的一系列段寄存器;“段名称”则是之前定义过的段的名字。 #### 实际应用案例分析 ##### 示例一:设置代码段 下面的例子展示了如何在一个简单的 DOS 应用程序里配置代码段: ```assembly assume cs:code ; 将cs假定为名为'code'的段 code segment ; 定义一个新段叫做'code' start: mov ax, 100 ; 设置ax=100 mov bx, 1000 ; 设置bx=1000 mul bx ; 进行16位乘法操作,结果分别保存在AX(DX:AX) mov ax, 4C00h ; 准备退出DOS环境 int 21h ; 调用中断服务例程结束程序运行 code ends ; 结束当前段定义 end start ; 表明整个程序入口点位于'start'处 ``` 在这个例子中,`assume cs:code` 明确指出了代码段由 `cs` 来表示,并命名为 `code` 。这样做的好处是在之后的操作过程中需要再重复声明 `cs` 的含义,使得代码更加简洁易懂。 ##### 示例二:多段配合使用 另一个更复杂的实例涉及到同类型的段以及它们之间的交互: ```assembly data SEGMENT ; 数据段开始 var DW ? ; 定义双字型未初始化的数据项 data ENDS ; 数据段结束 stack SEGMENT STACK 'STACK' ; 栈段开始 DB 256 DUP (?) ; 预留256个字节作为堆栈空间 stack ENDS ; 栈段结束 code SEGMENT USE16 ASSUME CS:code, DS:data, SS:stack ; 同时设定三个段的关系 main PROC FAR push ds ; 保护原有ds值 xor ax, ax push ax ; 初始化ss所指向的新栈底 mov ax,data mov ds,ax ; 加载数据段描述符至ds lea si,var ; 获取var的位置给si ... ret ; 返回调用者 main ENDP code ENDS END main ; 设定程序起点为主函数'main' ``` 在此片段内,仅设置了代码段 (`CS`) 和数据段 (`DS`) ,还额外设定了栈段 (`SS`) 。这种做法对于构建完整的应用程序框架非常有用,尤其是在需要管理复杂的数据流和控制流程的情况下。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值