汇编语言(寻址方式在结构化数据访问中的应用-王爽汇编语言第三版实验7)

问题提出:Power idea公司的基本情况如下:

       见书中数据列表:

下面格式已经定义好了这些数据:

assume cs:code 

data segment  

    db '1975','1976','1977','1978','1979','1980','1981','1982','1983'  

    db '1984','1985','1986','1987','1988','1989','1990','1991','1992'  

    db '1993','1994','1995' 

    ;以上是表示21年的21个字符串

    dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514  

    dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000  

    ;以上是表示21年 公司总收入的21个dword型数据

    dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226  

    dw 11542,14430,15257,17800

    ;以上是表示21公司雇员人数的21个Word型数据。

data ends  

table segment  

    db 21 dup ('year summ ne ?? ')  

table ends

code segment

start:

        ???????

        mov ax,4c00H

        int 21H

code ends

end start

实验要求:将data段中的数据,按照书中的格式写入到table段中,并计算21年中的人均收入(取整),结果也按照下面的格式保存在table段中。

实验分析:

       此实验定义并初始化了2个数据段(注意段的表示方法),从源内存段data中将数据读取出来后,按照一定的格式要求(有的数据需要处理)写入到目的内存段table中。

实验目的:

       1. 在一个数据段中定义不同的数据类型(字符、字符串和数值)的方式,并考察他们在内存中的存储情况。

       2. 掌握dup的用法。

       3. 考察我们对同一个数据段的内存单元,不同的寻址方式。

       4. 掌握DIV除法的基本应用。

       5. 怎样结构化的在内存中存储数据。

       6. 熟练掌握我们以前所学习的寄存器的用法,并归纳总结。

程序分析:

       考虑到此程序使用了2个数据段,并且我们同时要使用这2个数据段,我们除了使用通用的数据段寄存器DS外,另外使用ES寄存器来进行另外一个数据段的寻址。这样我们指定data段的段地址存储在DS中,table段的段地址存储在ES中。

       在data段中,我们观察并考虑怎样使用灵活多变的寻址方式来访问内存(这时候我们在脑海中应该有对于data段数据的内存存储有映像了)。通俗讲就是怎样在内存中寻址。

       1. 程序定义并初始化了data段,考虑程序中一共使用了3中数据类型,单字节类型(一个字节)、Word字类型(2个字节)、DW双字类型(4个字节)。它们在内存单元中所占用的连续空间是不同的。(问题提出:为什么要使用不同的数据类型?这个在C语言及其他高级语言中同样适用。不同的数据类型匹配不同的数据,做到合理安排数据在内存中存储,不浪费空间,提高运行速度。)

       因为在data段中,这些初始化的数据在内存中是连续存储的。(这时如果我们对于他们在内存中的存储有疑问,可以使用debug来查看下它们具体的存储情况,这样比较直观的体验下)。例如:部分存储情况(怎么来的?不写其他代码,编译连接debug后得出的):

data数据段:

       我们发现:.

       年份:在0b65:0000~0053H中存储的是21个字符串(没0结尾的)。(21个字符串它所占内存空间为21*4=84Bytes);黑色表示

       收入:在0b65:054~00A7H中存储的是21个dword数据(21个dword型数据,它所占内存空间为:21*4=84Bytes);(??看下开始,它们都是4字节的。第一个数存储的是10H,就是16,剩下3个高位单元都是00H,对了,它就代表是16;最后,68 97 5A 00 实际它是005A9768H=593700红色表示

       雇员人数:00A8~00D1中存储的是21个word型数据,它所占内存空间为:21*2 = 42Bytes;绿色表示。

       为什么后面的14个字节都是00H?是否浪费了?因为程序又重新定义并初始化了一个数据段用来存放year summ ne ??了。那么14个字节基本就是浪费了。

       这时候我们考虑怎样来表示data段中的内存(能够表示了,那么就代表能够寻址了)

table数据段:

       0B65:00E0开始是table数据段的内存地址了,如果偏移地址是0000H,那么它的段地址就是:0B73。   0B65:00E0H==0B73:0000H

       定义时使用了db语句,定义的字符串正好是16个字节,在debug中就是一行。重复21行,也就是在table数据段有21行的'year summ ne ?? '(体会这样的好处,省的在table数据段重复定义21次了,一个dup语句就搞定了。)

       强烈提示:这个是在debug中,为了显示方便,每行内存都是16个字节,但真正的内存是单列存储的,是没有行这个概念的。

对源数据的读取:    

       对于21个字符串的寻址:

       考虑到这个程序就是整个复制字符串,而不是修改它的内容,所以我们的寻址方式应该简化。考虑该字符串都是占用4个字节,那么我们使用ax寄存器操作2次就可以把一个字符串复制了;我们采用[bx+idata]方式寻址就可以了。其中idata(0,2)。一个字符串:例如1975占用4个字节的内存,其中[bx+0]=3139H,[bx+2]=3735H.

       bx的范围:0~83

       对于21个dword型数据的寻址:        

       同样道理,通过寄存器传送2个字就可以了。

       注意此时idata有变化了,idata初始值变成了84了(84,86)

       对于21个word型数据的寻址:

       同样道理,一个寄存器就搞定了。每次就一个字(8086CPU普通寄存器就是一个字),

       注意此时idata又有变化了,idata的初始值变成了168(0+84+84=168)。

对目标内存的写入:

       由于DS寄存器被使用了。我们不得不使用ES寄存器来存储table数据段的基地址(段地址)。(ES)= (table)

       由于bx变址寄存器被使用了(ax不能用、cx作为计数器、dx呢做除法去了。呵呵),我们再使用其他的个变址寄存器之一就行了。

       我们可以使用si寄存器。那么通过es:si就可以对目标内存进行寻址了。

       还有一个问题就是对于雇员数的地址,它的规律是每次+2的偏移,需要再搞个寄存器来进行变址,我这用了di。(因为在前面2个数据都是4个字节的,偏移量+4可以,但雇员数应该是+2)

       对于空格的处理:由于空格的ASCII码是:32(20H)。占用一个字节。这时候我们要注意传送的是一个字节,不是一个字,故应该使用的是8位寄存器,例如:al。

       关于结构化内存的写入:我们发现实验中要求我们在一行(16个字节中)正好写入这些数据(包括空格),那么我们注意空格的写入会导致在变址寄存器变量的有规律变化,在debug中就是按照一行的内存显示,其实他们的规律变化都是基于16个字节。

       表格一行的组成如下(含偏移地址si=0000H,段地址在ES中,这个可以画图说明):

       年份(4个字节):(si)= 0000H~0003H   (si +0   is +2)

       空格:               (si)= 0004H                    (is+4)

       收入(4个字节):(si)= 0005H~0008H    (si +5   is + 7)

       空格                     (si)= 0009H          (si +9)

       雇员数(2个字节)(si)= 000aH~000bH        (si +10)

       空格:                  (si)= 000cH                   (si +12)

       人均收入(2个字节)(si)= 000dH~000eH            (si + 13)

       空格                            (si)= 000fH              (si + 15)

最终的代码如下:   

assume cs:codesg, ds:datasg
datasg segment
	db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
	db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
	db '1993','1994','1995'
	dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
	dd 345980,590827,803530,118300,1843000,2759000,3753000,4649000,5937000
	dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
	dw 11542,14430,15257,17800
datasg ends

stack segment
	dw 0,0,0,0,0,0,0,0
stack ends

table segment
	db 21 dup('year summ ne ?? ')
table ends

codesg segment
    
	start:mov ax, datasg
		  mov ds, ax
		  
		  mov ax, stack
		  mov ss, ax
		  
		  mov ax, table
		  mov es, ax
		  
		  mov bx, 0
		  mov si, 0
		  mov di, 0
		  mov cx, 21
	s:	  mov ax, [bx]
		  mov es:[si], ax
		  mov ax, [bx+2]
		  mov es:[si+2], ax
		  mov al, 20h
		  mov es:[si+4], al
		  
		  ;收入
		  mov ax, [bx+84]
		  mov es:[si+5], ax
		  push ax
		  mov ax, [bx+84+2]
		  push ax
		  mov es:[si+7], ax
		  mov al, 20h
	      mov es:[si+9], al
		  
		  ;雇员人数
		  mov ax, [di+168]
		  mov es:[si+10], ax
		  mov al, 20h
		  mov es:[si+12], al
		  
		  ;人均收入
		  pop dx
		  pop ax
		  div word ptr es:[si+10]
		  mov es:[si+13], ax
		  mov al, 20h
		  mov es:[si+15], al
		  
		  add bx, 4
		  add si, 16
		  add di, 2    ;雇员人数的增量
		  loop s
		  
		  mov ax, 4c00h
		  int 21h
codesg ends
end start

编译、连接后运行前数据段在内存中存储情况如下:


执行结束后如图:

实现中也可以不使用栈段,直接访问es段寄存器来做除法运算、也可以使用新的寄存器

程序总结:

       实验中将table看作一个结构性数据的数组,每个结构性数据中包含多个数据项,加深数据在内存中存储的形式,并在脑海中抽象出来。  

数据分析源自:http://blog.sina.com.cn/s/blog_171daf8e00102xce0.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值