九、访问内存的要素以及INC和LOOP指令和Debug使用方法的扩

1. 内存单元的访问方式(这里的不全,之后会进一步补充):

    1) 总共有四种方式:

        i. [立即数],但是在这种情况下只能作为源操作数(即第二个操作数,比如mov ax, [15]等),此时访问的内存是(ds:立即数),但是不能作为目的操作数(即第一个操作数),如果作为第一个操作数则编译器会将看做是一个普通的立即数而报错,比如mov [15], ax就会看成mov 15, ax而报错!一定要注意这点!

以下所有方式既可以作为源操作数也可以作为目的操作数,没有任何限制!

        ii. [bx],注意,必须是基地址寄存器bx,不能是其它寄存器,如ax等,都会报错的!此时访问的就是(ds:bx)单元;

        iii. 任意段寄存器(包括cs):[bx],中括号中的偏移地址也必须是bx而不能是其它寄存器,这种表示法就是段前缀表示法,只不过不写段前缀默认ds作为段基,加了段前缀就能精确定位到某一个段上了!

    2) 访问内存单元最重要的关键——确定内存单元的类型(是字节型的还是字型还是双字型的):一般类型是由另一个操作数来确定(即根据寄存器的类型推断出来),比如mov al, [bx]中因为al是字节型的,因此传送的就是8位内存单元,而mov ax, [bx]中ax是16位的,因此传送的是双字,而mov [bx], [bx + 2]由于无法参考出传送的是什么类型的会编译报错!同样mov [bx], 23H中也无法推断出传送数据的类型而编译报错!

**关于两个操作数都是内存单元的情况后面会补充,这里先不提(其实也是能实现的!但不过需要人为显示指定内存单元的类型)!


2. 自加指令inc:

    1) 该命令只有一个参数,就是寄存器(也可以是内存单元,但是内存单元需要指定类型,后面会补充,这里先不讲),但可能不能作用于立即数;

    2) 作用是让指定寄存器中的内容自加1,可能会越界,需要注意;

    3) 除了段寄存器不能运用这条之另外其余所有寄存器(包括sp、bp、di、si等,不管是8位、16位还是32位)都可以运用该指令;


3. 使用loop指令构造循环结构:

    1) 所有循环都需要有一个循环计数变量,loop指令也是一样,该计数变量存放在cx寄存器中;

    2) 执行loop指令的过程:先将cx中的内容-1,然后再判断其是否为0,如果为0则推出循环(其实就是继续执行代码中位于loop后面的语句),如果不为0(不是大于0而是非0)则跳到loop指令中指定的那个标签的位置继续循环(其实就是将cs:ip指向标签处);

!汇编中的标签在编译后将会被替换成一个地址常量,定义方式和C语言中标签的定义方式相同,都是"标签名:"放在某个语句开头处;

    3) 一般步骤:

	mov		cx, 循环次数
tag:  循环起始位置
	循环体
	loop	tag


4. 示例:

    1) 计算2^12:

assume cs:codesg

codesg segment
	mov		ax, 1
	
	mov		cx, 12
lop:
	add		ax, ax
	loop	lop

	mov		ax, 4C00H
	int		21H
codesg ends

end
注意!对于立即数,如果不加后缀H就表示十进制数,如果加后缀H就表示是16进制数;

    2) 计算123×236:

assume cs:codesg

codesg segment
	mov		ax, 0
	
	mov		cx, 123
lop:
	add		ax, 236
	loop	lop

	mov		ax, 4C00H
	int		21H
codesg ends

end
    3) 将FFFF:0006字节中的值乘以3存入BX中

assume cs:codesg

codesg segment
	mov		ax, 0FFFFH
	mov		ds, ax
	mov		ax, 0
	mov		al, ds:[6]

	mov		bx, 0
	mov		cx, 3
lop:
	add		bx, ax
	loop	lop

	mov		ax, 4C00H
	int		21H
codesg ends

end
!! 注意:关于MASM中立即数表示问题的小结:

       *1. 立即数字只能以数字打头而不能以字母打头,否则会编译报错;

       *2. 因此像诸如AB、A00、FFFF等数据都将是非法的,而解决方法就是是在这些数前面加上一个0作为前缀;

       *3. 以后缀辨别进制类型,十进制无后缀,二进制后缀为B,十六进制后缀为H,如果数字中有A~F而没有后缀H也会编译报错!

!关于书写规范问题的建议:汇编编译器是不区分大小写的,但是通常指令和标记都用小写,而立即数中的字母(A~F以及后缀都是用大写),这样使程序更加直观;

    4) 求FFFF:0开始的13个字节内容之和(保存在DX寄存器中):

assume cs:codesg

codesg segment
	mov		ax, 0FFFFH
	mov		ds, ax
	mov		bx, 0

	mov		dx, 0
	mov		ah, 0

	mov		cx, 13
lop:
	mov		al, [bx]
	add		dx, ax
	inc		bx
	loop	lop

	mov		ax, 4C00H
	int		21H
codesg ends

end
注意!13个字节内容之和可能会超过8位,因此需要保存在16位寄存器,因此内存取出的字节要先放到ax中中转,然后再拿去和dx加!


6. 利用P命令和G命令调试循环程序:

    1) 当循环次数非常大时单步调试明显不现实,此时可以使用P或G命令将剩余循环全部执行完(P是Proceed,即继续的意思,G就是Go的一次,但和C语言的goto语句不通,goto是直接跳跃,而G命令不仅跳跃到指定位置,并且将其中所有的代码都执行完);

    3) G:

        i. G命令的参数是偏移地址,不能含段基地址,而段基默认就是CS(且不能改),因此进入调试程序后,可以先用U命令反汇编即将执行的汇编指令,每条汇编指令的偏移地址都将被显示出来,然后再根据显示的地址选择想要到达的目的地偏移地址即可;

        ii. 执行命令后就会从当前指令处一直连续执行到目的指令处,中间所有的代码都会被执行(包括循环);

        iii. 目的指令地址必须大于当前指令地址否则调试将会异常终止而返回Debug程序;

        

        可以看到G不是跳转而是一直连续执行到指定指令出,也就是说中间的所有指令都执行过了,可以从BX中的结果看出中间的循环都执行完了;

    3) P:

        i. 在遇到int指令(即中断指令)时使用P将会成功的结束程序回到Debug,这在之前已经运用过了;

        ii. 当遇到loop指令使用P命令,将会将剩余的循环一次性全部走完,一直走到最后一次loop指令的后面一条指令处;

        iii. 当遇到非上述两种指令的普通指令时,效果就跟T命令一样,仅仅就是“单步继续执行指令”的意思了;

        

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值