学汇编,记笔记(四)《汇编语言》王爽著——[BX]和loop

215 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

学习教材:《汇编语言(第4版)》王爽著 此笔记是书中内容+自我总结,方便查阅和复习 请支持原著

约定[bx]符号、(bx)符号、idata符号

前面提到,[0]可以表示某段偏移地址为0的那个内存单元,它有自适应功能:

mov ax,[0] //表示将字单元[0][1]传入ax
mov al,[0] //表示将字节单元[0]传入al

因此,类似于上面的用法:[bx]表示某段偏移地址为bx值的那个内存单元,此时偏移地址存在bx内

注意:只有bx、bp、si、di四个寄存器可以用[...]的形式寻址

为了区分且使描述方便,定义(bx)表示bx存储的内容,可以是寄存器(ax)、段寄存器+偏移地址((ds)*16+(bx))和内存单元(10000H)

(2000:0)、((ds):1000H)等是错误用法,必须前后统一

idata表示任意常量,可以是1,2,3,...

@[toc]

一、loop

loop指令表示循环,循环次数存储在寄存器cx里,格式为loop 标号,在循环体的第一行添加标号以表明循环入口。这是一个两次自增的循环:

assume cs:cal
cal segment
	;初始化
	mov ax,1
	mov cx,2
	;循环体
	s:add ax,ax
	loop s
	;返回值
	mov ax,4c00h
	int 21h
test ends
end

这里的s是一个标号,可以任取不限定于s

CPU执行Loop指令时分作两步

  1. (cx) -= 1
  2. 判断cx是否为0,不为0则转至运行标号处代码,否则向下执行

实验:加法循环计算123*236

累加123个236即可得到答案

assume cs:cal
cal segment
	mov ax,0
	mov cx,123
	s:add ax,236
	loop s
	mov ax,4c00h
	int 21h
cal ends
end

二、遍历连续的内存单元

假设需要遍历FFFF:0~FFFF:B这十二个内存单元,累加它们的值放到dx,传统方法是写十二个add,这里我们可以用循环

inc指令表示将某寄存器的值加一,如inc bx

需要注意的是:

  • 内存单元是一字节,而ax是十六位寄存器,存储元件的数据长度不一样不能直接赋值,因此需要分别对ah赋值0,对al赋值(FFFF:[bx]), 其他方法可能会引起进位丢失等情况

  • 汇编源程序中,数据不能以字母开头,FFFFH要写作0FFFFH

     assume cs:ffff0_12
     ffff0_12 segment
     	mov ax,0FFFFH
     	mov ds,ax
    
     	mov bx,0
     	mov cx,12
     	mov dx,0
     	
     	s:mov al,[bx]
     	mov ah,0
     	add dx,ax
     	inc bx
     	loop s
     	
     	mov ax,4c00h
     	int 21
     	
     ffff0_12 ends
     end
    

三、Debug.exe和MASM的不同处理

对于mov ax,[0],希望表示将ds:0内存单元的值送入ax,然而:

  • MASM会将其当作mov ax,0
  • Debug.exe会将其当作mov ax,ds:0

为了避免歧义,建议使用以下形式:

  1. mov al,ds:[0],(al)=((ds)*16+0)
  2. mov al,[bx],其中bx=0,(al)=((ds)*16+(bx))

四、段前缀

由于上方提到的差异处理,建议对偏移地址均添加对应的段前缀,避免歧义且便于理解

  • mov ax,ds:[bx/0]
  • mov ax,cs:[bx/0]
  • mov ax,ss:[bx/0]
  • mov ax,es:[bx/0]

五、安全的内存

随意向任意内存写入内容是危险的!

在一般的PC机中,DOS模式下安全的空闲的空间是00200H~002FFH,总长256B,可以供我们操作

谨慎起见,使用前先Debug查询,只有全是0才能安全使用

六、Debug调试loop

  • g (偏移地址)用于跳转到指定行运行,该段代码之前的命令会先运行,断点设置在指定行
  • p用于一步执行完loop循环,使用前先跳转到loop行

后记

  1. 编程中发现segment不能命名为test(?存疑)
  2. loop的原理是先减再判定再执行
  3. cx记录循环次数
  4. 良好的习惯:段前缀
  5. 不要随意写入
  6. 内存单元到寄存器的数据送入需要分两段送入,前者大小1B,后者大小2B