第八章 数据处理的两个基本问题
8.6 综合应用
示例代码 1:
assume cs:codesg,ds:datasgdatasg segmentdb 1024 dup (0)
datasg endscodesg segmentstart:mov ax,datasgmov ds,axmov bx,60h ; 确定记录地址 ds:bxmov word ptr [bx+0ch],38 ; 排名字段改为 38add word ptr [bx+0eh],70 ; 收入字段增加 70mov si,0mov byte ptr [bx+10h+si], 'V' ;用 si 来定位产品字符串中的字符inc simov byte ptr [bx+10h+si], 'A' inc simov byte ptr [bx+10h+si], 'X'mov ax,4c00hint 21hcodesg ends
end start
debug 的 反汇编结果截图:
示例代码 2( 使用 C 语言风格 ):
assume cs:codesg,ds:datasgdatasg segmentdb 1024 dup (0)
datasg endscodesg segmentstart:mov ax,codesgmov ds,ax mov bx,60h ;记录首地址mov word ptr [bx].0ch, 38 ; 排名字段改为 38, 相当于 C 中的 dec.pm = 38 add word ptr [bx].0eh, 70 ; 收入字段增加 70, 相当于 C 中的 dec.sr = dec.sr + 38mov si,0 ; 相当于 C 中的 i = 0mov byte ptr [bx].10h[si], 'V' ; dec.cp[i] = 'V'inc si ; i++mov byte ptr [bx].10h[si], 'A' ; dec.cp[i] = 'A'inc si ; i++mov byte ptr [bx].10h[si], 'X' ; dec.cp[i] = 'X'mov ax,4c00hint 21h
codesg ends
end start
debug 的 反汇编结果截图:
可以看到反汇编结果和上面的结果是一样的。
8.7 div 指令 ( 除法 指令 )
运行截图:
8.8 伪指令 dd ( 定义 双字 )
8.9 dup 指令 ( 数据的重复 )
实验 7
示例代码 1( 使用绝对定位 ):
assume cs:codesg,ds:datadata segmentdb '1975','1976','1977','1978','1979','1980','1981','1982','1983'db '1984','1985','1986','1987','1988','1989','1990','1991','1992'db '1993','1994','1995';84字节。总共 21 个年份,一个年份4个字节,总共 84 字节dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000;84字节dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226dw 11542,14430,15257,17800;通过计算得到每一个代码段相对于起始的偏移量
data ends table segmentdb 21 dup('year summ ne ?? ')
table endscodesg segmentstart:mov ax,datamov ds,ax;mov ax,table;mov es,axsub bx,bx ; mov bx,0sub di,di ; mov di,0mov cx,21;日期导入write_data:mov ax,ds:[di]mov ds:[bx+224],ax ; 224为从data段起始跳到table起始 add di,2 ; 日期为四个字节一组,而16位寄存器最大只能存两个字节,所以每次加二 mov ax,ds:[di] mov ds:[bx+226],ax add di,2 add bx,16 ;在table字段里换行输入日期 loop write_data sub bx,bx mov cx,21 ;收入导入wite_salary:mov ax,ds:[di] ;此di是上段循环最后的di,没有重置mov ds:[bx+229],ax ;229为从data段起始跳到table段收入输入的起始 add di,2 ;收入为四个字节一组,而16位寄存器最大只能存两个字节,所以每次加二 mov ax,ds:[di] mov ds:[bx+231],ax add di,2 add bx,16 ;在table字段里换行输入收入 loop wite_salary sub bx,bx mov cx,21;雇员数导入write_employees:mov ax,ds:[di] ;此di是上段循环最后的di,没有重置mov ds:[bx+234],ax ;234为从data段起始跳到table雇员数输入的起始 add di,2 add bx,16 ;在table字段里换行输入雇员数 loop write_employees sub di,di ;数据来源不再是数据段的顺序读取 sub bx,bx sub si,si mov cx,21;人均收入导入write_average:mov ax,ds:[di+84] ;定位到收入起始,将收入数据导入ax,dx中mov dx,ds:[di+86] div word ptr ds:[si+168] ;定位到雇员数起始 mov ds:[bx+237],ax ;将算数结果存入table的人均收入位置 add di,4 add si,2 add bx,16 ;在table字段里换行输入人均收入 loop write_averagemov ax,4c00hint 21h
codesg ends
end start
示例代码 2:( 使用相对定位 )
assume cs:codesg,ds:datasgdatasg segmentdb '1975','1976','1977','1978','1979','1980','1981','1982','1983'db '1984','1985','1986','1987','1988','1989','1990','1991','1992'db '1993','1994','1995';84字节。总共 21 个年份,一个年份4个字节,总共 84 字节dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000;84字节。收入总共 21 个字段,每个字段4个字节,总共 84 字节dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226dw 11542,14430,15257,17800;通过计算得到每一个代码段相对于起始的偏移量
datasg ends tablesg segmentdb 21 dup('year summ ne ?? ')
tablesg endscodesg segmentstart:mov ax,datasgmov ds,axmov ax,tablesgmov es,ax; bx 指示 table 段中每一行首地址,因为每一行都占16个字节,所以bx步长是16sub bx,bx ; mov bx,0 bx置为0,指向 tablesg 头sub di,di ; mov di,0mov cx,21;日期导入write_date:mov ax,ds:[di]mov es:[bx][0],axadd di,2 ; 日期为四个字节一组,而16位寄存器最大只能存两个字节,所以每次加二 mov ax,ds:[di] mov es:[bx][2],ax add di,2 add bx,16 ; 在table字段里换行输入日期 loop write_date sub bx,bx ;bx置为0,指向 tablesg 头mov cx,21 ;收入导入wite_salary:mov ax,ds:[di] ;此di是上段循环最后的di,没有重置mov es:[bx+5],ax ;table段收入输入的起始 add di,2 ;收入为四个字节一组,而16位寄存器最大只能存两个字节,所以每次加二 mov ax,ds:[di] mov es:[bx+7],ax add di,2 add bx,16 ;在table字段里换行输入收入 loop wite_salary sub bx,bx ;bx置为0,指向 tablesg 头mov cx,21;雇员数导入write_employees:mov ax,ds:[di] ;此di是上段循环最后的di,没有重置mov es:[bx+10],ax ;雇员数的起始地址 add di,2 add bx,16 ;在table字段里换行输入雇员数 loop write_employees sub di,di ;数据来源不再是数据段的顺序读取 sub bx,bx sub si,si mov cx,21;人均收入导入write_average:mov ax,es:[bx][5] ;定位到收入起始,将收入数据导入ax,dx中mov dx,es:[bx][7] div word ptr es:[bx][10] ;定位到雇员数起始 mov es:[bx][13],ax ;将算数结果存入table的人均收入位置 add bx,16 ;在table字段里换行输入人均收入 loop write_averagemov ax,4c00hint 21h
codesg ends
end start
第一个循环执行年份输入,第二个收入输入,第三个雇员数输入,第四个人均收入输入,在人均收入的数据获取时使用div除法运算得到数据源
运行截图:
示例代码 3( 使用一次循环 ):
assume cs:codesgdata segmentdb '1975','1976','1977','1978','1979','1980','1981','1982','1983'db '1984','1985','1986','1987','1988','1989','1990','1991','1992'db '1993','1994','1995';84字节。总共 21 个年份,一个年份4个字节,总共 84 字节dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000;84字节dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226dw 11542,14430,15257,17800;通过计算得到每一个代码段相对于起始的偏移量data endstable segmentdb 21 dup ('year summ ne ?? ')
table endscodesg segment
start: mov ax,data ;取得数据段mov ds,axmov ax,tablemov es,axmov cx,21mov si,0mov di,0mov bx,0s: ;把年份送到table中mov ax,ds:[bx]mov es:[di+0],axmov ax,ds:[bx+2]mov es:[di+2],ax;把收入送到table中mov ax,ds:[bx+84]mov es:[di+5],axmov ax,ds:[bx+86]mov es:[di+7],ax;转移雇员人数mov ax,ds:[168+si]mov es:[di+10],ax;计算人均收入并把其送到table中mov ax,ds:[84+bx]mov dx,ds:[86+bx]div WORD ptr ds:[168+si]mov es:[di+13],axadd si,2 ; 数据段中 雇员人数是 2 字节偏移量 add bx,4 ; 数据段中 年份 和 收入都是 4字节偏移量add di,16 ; table 表中行偏移量loop smov ax,4c00hint 21h
codesg ends
end start
截图( 注意看编译后可执行程序的文件名,masm编译汇编程序的时候,其源文件名不能超过8位,超过8位时,会自动编译成不知道什么名称,我的源文件名是 shiyan_7_2.asm,已经超过8位,生成的可执行程序名是 shiyan~2.exe ):