今天学习了王爽《汇编语言》第5、6章。
我感觉这两章主要加深了对于段这个概念的理解。
第5章[Bx]和loop指令,重点在于段地址和偏移地址的理解,段前缀的应用。
第6章包含多个段的程序,重点在于理解为什么要分段,掌握分段汇编程序的写法,搞清楚段在内存当中的存储。
1.loop指令
和[bx]
的应用
1.1 计算ffff:0~ffff:b
单元中数据的和,并将结果保存在dx
中?
存在的问题:8位的内存单元累加之和放到16位的寄存器中。
解决的方法:以ax
为中介,其中ah
设为0,al
为内存单元的值。
mov ax,0ffffh
里面,0
和h
一个都不能少。
assume cs:code
code segmentmov ax,0ffffhmov ds,axmov ax,0mov dx,0mov bx,0mov cx,12s:mov al,[bx]add dx,axinc bxloop s mov ax,4c00hint 21h
code ends
end
1.2 将内存ffff:0~ffff:b
单元中的数据复制到0:200~0:20b
中?
段前缀的应用,ds、cs、ss、es
都可以使用,很灵活。
注意题目是,将内存ffff:0~ffff:b
单元中的数据复制到0:200~0:20b
单元中。将段前缀设置为0020h
比0
要方便。
mov ax,0ffffhmov ds,axmov ax,0020hmov es,axmov bx,0mov cx,12
s: mov dl,[bx]mov es:[bx],dlinc bxloop s
2.包含多个段的程序
2.1 如何对数据进行累加?
即一些数据常量应该如何声明,如何引用?
采用dw 0123h,0456h,0789h
进行声明。
通过cs:[bx]
进行定位,bx
每次增加2个字节。
但是仅仅只做这些改变,在运行时就会出现问题。先看一下程序的内存:
可以看出前6个字节存储的三个字的值,为避免将数据当作指令,程序应该从0C53:0006开始执行。
所以需要在源程序中用end
标号,标记程序的入口地址。
2.2 利用栈,将程序中定义的数据逆向存放?
首先,提前声明一块空间,供栈使用。
另外,设置好栈的段地址和偏移地址。
示例程序如下:
assume cs:code
code segmentdw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987hdd 0,0,0,0,0,0,0,0start:mov ax,csmov ss,axmov sp,30hmov bx,0mov cx,8s: push cs:[bx]add bx,2loop smov bx,0mov cx,8s1:pop cs:[bx]add bx,2loop s1mov ax,4c00hint 21hcode ends
end start
2.3 结构更清晰——将代码分多个段
下面是之前提及的例子,不过分了数据、栈和代码三段。
需要注意的是:
1.在assume
之后,CPU不会将CS指向code,不会将DS指向data,不会将SS指向stack。
2.end
指明了程序的入口,这个入口将被写入可执行文件的描述信息。可执行文件中的程序被加载到内存之后,CPU的CS:IP被设置指向这个入口,开始执行程序中的第一条指令。
所以,CS的值不用在代码中设定,但是DS和SS的值需要在代码中进行说明。
3.对于一个段,如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为:
(N/256+1)*256
其中除法取整。
assume cs:code,ds:data,ss:stackdata segmentdw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data endsstack segmentdw 0,0,0,0,0,0,0,0
stack endscode segment
start: mov ax,stackmov ss,axmov sp,20h mov ax,datamov ds,axmov bx,0mov cx,8
s: push [bx]add bx,2loop smov bx,0mov cx,8
s1: pop [bx]add bx,2loop s1mov ax,4c00hint 21h
code ends
end start
自己通过调试,发现段在内存中的存储方式,是很有意思的一件事情。
不过更有意思的永远都在后面(手动滑稽)