目录
一.实验内容:
问题:
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段中。
二.实验过程(实验设计思路,源码及注释)
程序分析:
先观察data段,21个年份一共占21*4=84byte,21个公司收入一共占21*4=84byte(因为dword占4byte),21个公司雇员人数占21*2=42byte。再观察table段,dup表示复制,复制了21次'your sum ne ?? ',因为这个字符串占16个字节,这样我们就可以用date段中的21个年份替换table段中的year(例如,1975 -> year),同样我们可以用data段中的21个公司总收入替换table段中的summ,data段中的雇员人数替换table段中的ne,将data段人均收入的结果用??来替换,这样就完成了table段数据的替换。
考虑到仅仅是将data段中的数据复制到table段中,而不是修改内容并覆盖,这样我们的话,我们可以通过地址传递的方式完成数据的复制操作。那么应该如何具体操作呢?
我们可以具体分析一下复制的一个规律,如下图:
我们可以进行模拟,第一次data:[0] --> table:[0],第二次data:[1] --> table:[1],……
data:[4] --> table:[5],四个一循环,这样我们可以用[bx+si]存放data的偏移地址,但由于ds已经用来存储data的段地址了,所以我们只能用ss或者es来存储table的段地址(基地址),这里我们用ss段地址(如果用ss作为table的段地址,bp的段地址默认在ss中。可以不用写段名doge)。这里再解释一下为什么不给sp赋初值,因为我们只用到了栈段,用不到push和pop操作,所以不需要给sp赋值。
那么我们怎么计算人均收入呢?人均收入 = 公司总收入 / 雇员人数,由于公司总收入为dword型数据(占32bit)需要ax和dx两个联合存放,而雇员人数为word型数据(占16bit)
下面是最终的源码:
assume cs:codesg,ds:data,es:table
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'
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11452,14430,15257,17800
data ends
table segment
db 21 dup ('year summ ne ?? ')
table ends
codesg segment
start: mov ax,data
mov ds,ax ;这两行是将data段的地址通过ax寄存器送到ds寄存器中
mov ax,table
mov ss,ax ;这里也可以用es寄存器
mov bx,0
mov si,0
mov bp,0 ;初始化bx,si,bp
mov cx,21 ;cx寄存器存储循环次数21次
s0:mov ax,[bx+si]
;s0写入年份
mov [bp+0],ax;相当于data:[bx+si] --> table:[bp+0]
add si,2 ;因为ax寄存器是16位(2byte)寄存器,所以移动2个字节(如,‘19’)
mov ax,[bx+si]
mov [bp+2],ax
add si,2
add bp,10h ;10h表示10进制数16
loop s0
mov cx,21
mov bp,0
mov si,0 ;由于cx,bp,si的值已经变换,需要重新赋值
s1:mov ax,[bx+si+84] ;跳过年份所占的84byte
;s1写入公司总收入
mov [bp+5],ax;相当于data:[bx+si+84] --> table:[bp+5]
add si,2
mov ax,[bx+si+84]
mov [bp+7],ax
add si,2
add bp,10h
loop s1
mov cx,21
mov bp,0
mov si,0 ;重新初始化
s2:mov ax,[bx+si+168]
;s2写入公司雇员人数
mov [bp+10],ax
add si,2
add bp,10h
loop s2
mov cx,21
mov bp,0 ;后面不用si不需要对si重新赋值
s3:mov ax,[bp+5];ax存低16位总收入数据
;s3计算人均收入并写入
mov dx,[bp+7] ; dx存高16位总收入数据
div word ptr [bp+10] ;商存在ax中,余数存在dx中
mov [bp+13],ax ;相当于ax --> table:[bp+13]
add bp,10h
loop s3
mov ax,4c00h
int 21h
codesg ends
end start
三.Debug调试及实验结果分析
先用debug分析一下在最初data段的存储情况,如下图:
我们可以观察:
红色圈:在075A:0100 ~ 075A:0153存储的是21个年份数据共占84byte
蓝色圈:在075A:0154 ~ 075A:01A7存储的是21个收入数据共占84byte
紫色圈:在075A:01A8 ~ 075A:01D1存储的是21个雇员数据共占42byte
在075A:01E0后面存的是table段中的数据“year sum ne ??”……
再用debug分析一下执行最终代码后table段中的数据,如下图:
成功将data段中的数据写入到table段中!!!
四.总结与体会
1.本实验考查知识较多,涉及除法指令、dup复制、基址间接寻址等操作全面考查了实验者的综合实践能力。
2.当一个ds寄存器不够用时,可以选择es寄存器或者ss寄存器来进行存储。
3.当我们仅对代码进行复制操作(并不改代码)时,我们可以仅修改地址来实现复制操作。
4.可以结合图表进行分析,对数据进行模拟总结其规律。