王爽《汇编语言》(4-6章)学习笔记

《汇编语言》王爽–学习笔记

参考链接

三、第一个程序

先看一段简单的汇编语言源程序

assume cs:codesg

codesg segment

	mov ax,0123H
	mov bx,0456H
	add ax,bx
	add ax,ax

	mov ax,4c00
	int 21H

codesg ends

end

对程序进行说明:

  • XXX segment ··· ··· XXX ends
    • segment和ends成对出现,代表一个段的开始和结束。
    • 一个汇编程序是由多个段组成的,这些段被用来存放代码,数据或当作栈空间来使用。一个有意义的汇编程序至少要有一个段(存放代码)。
  • end
    • end:一个汇编程序结束的标记,遇到end后编译器停止编译。
  • assume
    • 含义为“假设”,假设某一个段寄存器和程序中的某一个用segment ···ends 定义的段关联。
    • 可以理解为将这个段寄存器指向程序段的段地址
  • 标号(codesg)
    • 一个标号指代一个地址
  • 程序返回 mov ax, 4c00 int 21H
    • 这两条指令代表程序返回

1.汇编程序从写出到执行的过程

img

2. 程序执行过程

DOS系统中 .EXE文件中的程序的加载过程

img

四、[BX] 和 loop指令

1. [bx] 和 loop指令

[bx] :同样表示一个内存单元,它的偏移地址在bx中,段地址默认在ds中。

loop(循环)指令:loop 标号,CPU执行loop指令的时候,要进行两步操作:

  1. (cx) = (cx) - 1;
  2. 判断 cx 中的值,不为零则转至标号处执行程序,如果为零则向下执行。

程序示例:编程计算2^12。

assume cs:code 

code segment 
	mov ax, 2
	
	mov cx, 11 
s:  add ax, ax 	;汇编中,这的标号s 实际标识了一个地址,这个地址处有一条指令:add ax,ax。
	loop s     
	
	mov ax,4c00h 
	int 21h 
code ends 
end

用 cx 和 loop 指令相配合实现循环功能的程序框架如下:

	mov cx,循环次数
s:
	循环执行的程序段
	loop s

2. Debug和masm编译器对指令的不同处理

形如 mov ax,[idata] 的指令在Debug和masm中有着不同的解释:

Debug是将它解释为 “[idata]” 是一个内存单元,“idata” 是内存单元的偏移地址;

而编译器masm中则是将 “[idata]” 解释为“idata”。

  • 解决方法1:先将偏移地址送入BX,然后再使用mov ax,[bx]

  • 解决方法2:直接在 “[ ]” 的前面显式地给出段地址所在的段寄存器,如 mov al, ds:[0]

    这种写法通过编译器之后会变成Debug中的 mov al,[0]

拓展:

这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的“ds:”,“cs:”,“ss:”,“es:”,在汇编语言中称为段前缀

3. loop 和 [bx] 的联合应用

直接看例子:

计算ffff:0 ~ ffff:b单元中的数据的和,结果存储在 dx 中

分析:

  1. 这些内存单元都是字节型数据范围0 ~ 255 ,12个这样的数据相加,结果不会大于65535,可以在dx中存放下。
  2. 对于8位数据不能直接加到16位的寄存器 dx 中。
  3. 如果仅向 dl 中累加 12 个 8 位数据,很有可能造成进位丢失。

解决方案:

用一个16位寄存器来做中介。将内存单元中的8位数据赋值到一个16位寄存器a中,再将ax中的数据加到dx,从而使两个运算对象的类型匹配并且不会越界。


assume cs:code 

code segment 
	mov ax, 0ffffh ;在汇编源程序中,数据不能以字母开头,所以要在前面加0
	mov ds, ax 
	mov bx, 0   ;初始化ds:bx指向ffff:0
	mov dx, 0   ;初始化累加寄存器dx,(dx)= 0
	
	mov cx, 12  ;初始化循环计数寄存器cx,(cx)= 12
s:  mov al, [bx]
	mov ah, 0
	add dx, ax  ;间接向dx中加上((ds)* 16 +(bx))单元的数值
	inc bx      ;ds:bx指向下一个单元
	loop s 
	
	mov ax, 4c00h 
	int 21h 
code ends 
end

4. 安全的编程空间

之前没有提到的一个问题,如果在写程序之前不关注要操作的内存,直接开始使用,如果改写了内存中重要的系统数据,可能会引起系统崩溃。可见,在不能确定一段内存空间中是否存放着重要数据或代码的时候,不能随意向其中写入内容。

一般操作系统和合法程序都不会使用0:200~0:2ff这256个字节的空间,所以可以使用这段安全的空间。

学习汇编语言,要通过它来获得底层的编程体验,理解计算机底层的基本工作机理。所以我们尽量直接对硬件编程,而不理会操作系统。

这在纯DOS方式(实模式)下是可以做到的,但在windows或Unix这种运行与CPU保护模式的操作系统上是不可能的,因为这种操作系统已经将CPU全面严格的管理了。

五、包含多个段的程序

一个问题:根据什么设置CPU的 CS:IP 指向程序的第一条要执行的指令?

这一点,是由可执行文件中的描述信息指明的。在一个程序文件中,用伪指令end描述程序的结束和程序的入口。

在编译,连接后,由“end start”指明的程序入口被转化为一个入口地址,存储在可执行文件的描述信息中。

当程序被加载入内存之后,加载者从程序的可执行文件的描述信息中读到程序的入口地址,设置CS:IP。这样CPU就从我们希望的地址处开始执行。

在代码段中使用数据

示例:利用栈,将程序中定义的数据逆序存放

assume cs:codesg 

codesg segment 
	dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ; 0:0~0:15单元
	dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 0:16~0:47单元的空间作为栈使用
			
start:	mov ax, cs 
	    mov ss, ax 
	    mov sp, 30h ;将设置栈顶ss:sp指向栈底cs:30
		
	    mov bx, 0
	    mov cx, 8
	 s: push cs:[bx]
	    add bx, 2
	    loop s    ;以上将代码段0~15单元中的8个字型数据依次入栈
		
	    mov bx, 0
		mov cx, 8
	s0:	pop cs:[bx]		
		add bx,2
		loop s0   ;以上依次出栈8个字型数据到代码段0~15单元中
			
		mov ax,4c00h 
		int 21h 
codesg ends 
end start	;指明程序的入口在start处

在描述dw的作用时,不仅可以说用它来定义数据,也可以说用它来开辟内存空间留给之后的程序使用。

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

assume cs:code,ds:data,ss:stack 

data segment 
	dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ;0-15单元
data ends 

stack segment 
	dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;0-31单元
stack ends 

code segment 
start:	mov ax, stack	;将名称为“stack”的段的段地址送入ax
		mov ss, ax
		mov sp, 20h  	;设置栈顶ss:sp指向stack:20
		
		mov ax, data 	;将名称为“data”的段的段地址送入ax
		mov ds, ax   	;ds指向data段			
		mov bx, 0    	;ds:bx指向data段中的第一个单元
		
		mov cx, 8
	s:  push [bx]
		add bx, 2
		loop s       ;以上将data段中的0~15单元中的8个字型数据依次入栈
			
		mov bx, 0
		
		mov cx, 8
	s0:	pop [bx]
		add bx, 2
		loop s0      ;以上依次出栈8个字型数据到data段的0~15单元中
			
		mov ax, 4c00h 
		int 21h 
code ends
end start

总之,CPU到底如何处理我们定义的段中的内容,是当作指令执行,当作数据访问,还是当作栈空间,完全是考程序中具体的汇编指令,和汇编指令对 CS:IP、SS:IP、DS 等寄存器 的设置来决定的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ClimberCoding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值