主题:这个程序不是有病毒,而是有鬼
;第171实验7:题之意为要把归类给出的数据重新编成一个较好看的表格。
assume cs:code,ds:data1,ds:data2,ds:data3
data1 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'
data1 ends
;21个年份●属字符串
data2 segment
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
data2 ends
;21年公司总收入●属双字型数据
data3 segment
dw 3, ,7, ,9, ,13, ,28, ,38, ,130, ,220, ,476, ,778, ,1001, ,1442, ,2258, ,2793, ,4037, ,5635, ,8226, ,11542, ,14430, ,15257, ,17800
data3 ends;未编start:部分先masm并d ss:0可预先在debug中看到这些数据。
;21年顾员人数变化●属字型数据
table segment
db 4210h dup(0);●●●●●●●为了显示,此区要设得足够大,将原杂数清0,否则会读到不正确数,导致div出问题●●●●●●●●
table ends
code segment
start:
mov ax,table
mov es,ax;通知地址
mov cx,21;●如果下面能搞好每年一行,那么cx=21就可以。
mov bx,0
mov si,0
mov bp,0
s21:
mov ax,data1
mov ds,ax;通知地址,年份占有数据区
push cx
mov cx,4
;mov di,0;●di是个不能乱用的东西!用上它后年份搬到es中竟全变成1111,妈的!
s1:mov al,ds:[si];读入不必bx(在前面的认识si例子中,si每次读一个字(定义为数字时),这次只读一个字节(定义为字符串时))
mov es:[bx],al;写入要用bx
inc bx
inc si
loop s1;完成年份填表。
mov ax,data2
mov ds,ax;通知地址,收入占有数据区
mov ax,ds:[bp];读收入,收入是双字,读法须有讲究吗?试把197514(=3038A=13DE:0000 8A 03 03 00)放在第一个,
mov dx,ds:[bp+2]
;●●●●●●与下面那个bp不同步,需修改
mov es:[bx+11],ax;填收入
mov es:[bx+13],dx
push ax;保护此数用于下面的除法运算
mov ax,data3
mov ds,ax;通知地址,人数占有数据区
mov ax,ds:[bp];读人数
add bp,4;这个改为+4后,收入填入正确了,为了让人数与此同步,在人数原始数据区每个数据间放个空格或0,问题应可园满解决了。
mov es:[bx+26],ax;填人数,根据debug d es:0确认bx+6
;上面三项成功完成。
;最后一项求人平均收入(●取整):须完全熟记168页故有规定才能搞好下面各项的关系(现未搞清,刚从除法那边抄来这段)已搞清楚。
pop ax
div word ptr es:[bx+26];●指明除数的位置及类型。
mov es:[bx+39],ax;填人平均收入
add bx,172;bx负责控制行,加12后第二次s21循环会从es:0的第二行写起。
pop cx;●有无设置栈及有无栈指针似乎关系不大,重要的是这两句顺序搞反cx和di的值便搞反!!!!
loop s21
;●●●●●●想先在此把年份后的三组数据读出来,转成字符后存在原数字后面
mov bx,0
mov cx,21
aa:mov si,0
push cx;●●●●●●●●●●●●●●●●可能是这句放在aa:上面(即放在循环外)引起的?是!!!!!!!!!!!!
mov ax,es:[bx+15];读收入,收入是双字,读法须有讲究吗?试把197514(=3038A=13DE:0000 8A 03 03 00)放在第一个,
mov dx,es:[bx+17];●怪,写入时明明是es:[11]处,实际处于es:[15]处
add si,18
call divdw
;●●●●●●发现debug有不稳定,昨晚转好1976年收入,到此要继续时两三次都自动跳出运行,今天却不会●●
;会不会是昨运行太久太热引起?
;●●●●跟踪显示1975直到1989收入803530写入没错,但1990的1183000却写11830,少了两个0,●所以divdw子程序还要修改:
;16000正常写入,因它是用第一部分处理的;1183000则分两部分处理,故第一部分的ax=0,及dx=0时不许结束●●●●●●
;但如此一来第一部分遇到全0时如何跳出循环?●●●●跟踪显示修改后最后一个收入也正确写入●●●●●●
;但运行却产生除法溢出提示,为什么?!!!!!!!!loop最后pop时发现cx=17ee,可见是cx发生错误,故在pop前加cx=0
;还是不行,还是cx=17ee.debug t=0 850到达1993年写收入处,用t继续.●改push cx位置后运行没再发出溢出警告
;若loop进入不断循环,则divdw子程序会读到0导致错误。
;●●●●●●●●●●●●●●●●此段完成收入转字符工作●●●●●●●●●●●●●●●●●●●●●●●●●●●●
mov dx,0
mov ax,es:[bx+30];读人数
mov si,30
call divdw;此段完成人数转字符工作●●●●●
add bx,176
pop cx
loop aa
;显示(因这里要单独占用一ds,所以不能在上面一边计算一边显示)
mov ax,0b800h
mov ds,ax;通知显存地址
mov bx,0
mov cx,21
kk:mov ax,0;不清0则al多读出数值.
mov al,es:[bx];读出
mov ds:[bx],al;写入显存区
mov byte ptr ds:[bx+1],02
mov al,es:[bx+1];读出
mov ds:[bx+2],al;写入显存区
mov byte ptr ds:[bx+3],02
mov al,es:[bx+2];读出
mov ds:[bx+4],al;写入显存区
mov byte ptr ds:[bx+5],02
mov al,es:[bx+3];读出
mov ds:[bx+6],al;写入显存区
mov byte ptr ds:[bx+7],02;●●●完成年份读写
;●●●●原来还有个错误,下面这些是数字,还没有调用前面设计的转换程序!!!!!!
mov ax,0
mov al,es:[bx+6];读收入
mov ds:[bx+20],al;写收入到显存区
mov byte ptr ds:[bx+21],02
mov al,es:[bx+8];第二位
mov ds:[bx+22],al
mov byte ptr ds:[bx+23],02
mov al,es:[bx+10];第三位
mov ds:[bx+24],al
mov byte ptr ds:[bx+25],02;●有个问题:前面那些数位数较少,没读到数会出现什么情况?●
mov al,es:[bx+12];第四位
mov ds:[bx+26],al
mov byte ptr ds:[bx+27],02
mov al,es:[bx+14];第五位
mov ds:[bx+28],al
mov byte ptr ds:[bx+29],02
mov al,es:[bx+16];第六位
mov ds:[bx+30],al
mov byte ptr ds:[bx+31],02
mov al,es:[bx+18];第七位
mov ds:[bx+32],al
;mov byte ptr ds:[bx+33],02;●怪,多此句就汇编失败?!第七位已读出显示白色,难道此位不能改颜色?
;●●●●想先完成年份和收入显示,成功后再增加后两项。●●●●●●●●●●●●
;mov ax,0;●●●●●●●●●●●●怪事!在此增加任何语句都导致汇编失败!!!!是否程序太长越段须far属性?●●●●
;mov al,es:[bx+22];读人数,;用debug u全部列出都在一个段中,那什么原因?
;mov ds:[bx+40],al;写人数到显存区
;mov byte ptr ds:[bx+41],02
;mov al,es:[bx+24];第二位
;mov ds:[bx+42],al
;mov byte ptr ds:[bx+43],02
;mov al,es:[bx+26];第三位
;mov ds:[bx+44],al
;mov byte ptr ds:[bx+45],02
;mov al,es:[bx+28];第四位
;mov ds:[bx+46],al
;mov byte ptr ds:[bx+47],02
;mov al,es:[bx+30];第五位
;mov ds:[bx+48],al
;mov byte ptr ds:[bx+49],02;●●发现此段搬到“call divdw;此段完成人数转字符工作●●●●●”下汇编就可以,见鬼,不知原因!
;难道与选ds做显存有关?
add bx,320;●●●●由160改为360后显出1995 5937000●可见须占领整个屏幕才能正常显示●●●●●●●●●●●●
loop kk
mov ax,4c00h
int 21h
;除法不溢出程序数字转显示字符字程序
divdw proc
mov cx,0ah;这个数是上面公式中的N
mov di,1000;●●要么写10进制mov bx,1000,要么写16进制mov bx,03e8h重点在于h●●
mov bp,0 ;●●跟踪显示上句处于t=0 380位置
cmp dx,0;先看看,若dx=0,则要处理的是小于65536
je qq;小于65536就跳过/1000的处理
div di
;得ax=12345,dx=666,即将12345666/1000分两部分处理
push ax
mov ax,dx
yy:mov ax,ax
mov dx,0
div cx;ax=66,dx=6
add dx,30h
mov es:[si+bx],dx;写到数据区,从右向左写
sub si,2
inc bp
cmp bp,3;不用ax=0作判断,而用是否已写了3次(无论是否是0)作判断!
je xx ;●遇到全0时如何跳出循环?写3个0就跳出写3个0就跳出
jmp yy
;处理12345
xx:pop ax
qq:mov ax,ax
mov dx,0
div cx;ax=66,dx=6
add dx,30h
mov es:[si+bx],dx;写到数据区,从右向左写
sub si,2
cmp ax,0
je qqq
jmp qq
qqq:
ret
divdw endp
code ends
end start
assume cs:code,ds:data1,ds:data2,ds:data3
data1 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'
data1 ends
;21个年份●属字符串
data2 segment
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
data2 ends
;21年公司总收入●属双字型数据
data3 segment
dw 3, ,7, ,9, ,13, ,28, ,38, ,130, ,220, ,476, ,778, ,1001, ,1442, ,2258, ,2793, ,4037, ,5635, ,8226, ,11542, ,14430, ,15257, ,17800
data3 ends;未编start:部分先masm并d ss:0可预先在debug中看到这些数据。
;21年顾员人数变化●属字型数据
table segment
db 4210h dup(0);●●●●●●●为了显示,此区要设得足够大,将原杂数清0,否则会读到不正确数,导致div出问题●●●●●●●●
table ends
code segment
start:
mov ax,table
mov es,ax;通知地址
mov cx,21;●如果下面能搞好每年一行,那么cx=21就可以。
mov bx,0
mov si,0
mov bp,0
s21:
mov ax,data1
mov ds,ax;通知地址,年份占有数据区
push cx
mov cx,4
;mov di,0;●di是个不能乱用的东西!用上它后年份搬到es中竟全变成1111,妈的!
s1:mov al,ds:[si];读入不必bx(在前面的认识si例子中,si每次读一个字(定义为数字时),这次只读一个字节(定义为字符串时))
mov es:[bx],al;写入要用bx
inc bx
inc si
loop s1;完成年份填表。
mov ax,data2
mov ds,ax;通知地址,收入占有数据区
mov ax,ds:[bp];读收入,收入是双字,读法须有讲究吗?试把197514(=3038A=13DE:0000 8A 03 03 00)放在第一个,
mov dx,ds:[bp+2]
;●●●●●●与下面那个bp不同步,需修改
mov es:[bx+11],ax;填收入
mov es:[bx+13],dx
push ax;保护此数用于下面的除法运算
mov ax,data3
mov ds,ax;通知地址,人数占有数据区
mov ax,ds:[bp];读人数
add bp,4;这个改为+4后,收入填入正确了,为了让人数与此同步,在人数原始数据区每个数据间放个空格或0,问题应可园满解决了。
mov es:[bx+26],ax;填人数,根据debug d es:0确认bx+6
;上面三项成功完成。
;最后一项求人平均收入(●取整):须完全熟记168页故有规定才能搞好下面各项的关系(现未搞清,刚从除法那边抄来这段)已搞清楚。
pop ax
div word ptr es:[bx+26];●指明除数的位置及类型。
mov es:[bx+39],ax;填人平均收入
add bx,172;bx负责控制行,加12后第二次s21循环会从es:0的第二行写起。
pop cx;●有无设置栈及有无栈指针似乎关系不大,重要的是这两句顺序搞反cx和di的值便搞反!!!!
loop s21
;●●●●●●想先在此把年份后的三组数据读出来,转成字符后存在原数字后面
mov bx,0
mov cx,21
aa:mov si,0
push cx;●●●●●●●●●●●●●●●●可能是这句放在aa:上面(即放在循环外)引起的?是!!!!!!!!!!!!
mov ax,es:[bx+15];读收入,收入是双字,读法须有讲究吗?试把197514(=3038A=13DE:0000 8A 03 03 00)放在第一个,
mov dx,es:[bx+17];●怪,写入时明明是es:[11]处,实际处于es:[15]处
add si,18
call divdw
;●●●●●●发现debug有不稳定,昨晚转好1976年收入,到此要继续时两三次都自动跳出运行,今天却不会●●
;会不会是昨运行太久太热引起?
;●●●●跟踪显示1975直到1989收入803530写入没错,但1990的1183000却写11830,少了两个0,●所以divdw子程序还要修改:
;16000正常写入,因它是用第一部分处理的;1183000则分两部分处理,故第一部分的ax=0,及dx=0时不许结束●●●●●●
;但如此一来第一部分遇到全0时如何跳出循环?●●●●跟踪显示修改后最后一个收入也正确写入●●●●●●
;但运行却产生除法溢出提示,为什么?!!!!!!!!loop最后pop时发现cx=17ee,可见是cx发生错误,故在pop前加cx=0
;还是不行,还是cx=17ee.debug t=0 850到达1993年写收入处,用t继续.●改push cx位置后运行没再发出溢出警告
;若loop进入不断循环,则divdw子程序会读到0导致错误。
;●●●●●●●●●●●●●●●●此段完成收入转字符工作●●●●●●●●●●●●●●●●●●●●●●●●●●●●
mov dx,0
mov ax,es:[bx+30];读人数
mov si,30
call divdw;此段完成人数转字符工作●●●●●
add bx,176
pop cx
loop aa
;显示(因这里要单独占用一ds,所以不能在上面一边计算一边显示)
mov ax,0b800h
mov ds,ax;通知显存地址
mov bx,0
mov cx,21
kk:mov ax,0;不清0则al多读出数值.
mov al,es:[bx];读出
mov ds:[bx],al;写入显存区
mov byte ptr ds:[bx+1],02
mov al,es:[bx+1];读出
mov ds:[bx+2],al;写入显存区
mov byte ptr ds:[bx+3],02
mov al,es:[bx+2];读出
mov ds:[bx+4],al;写入显存区
mov byte ptr ds:[bx+5],02
mov al,es:[bx+3];读出
mov ds:[bx+6],al;写入显存区
mov byte ptr ds:[bx+7],02;●●●完成年份读写
;●●●●原来还有个错误,下面这些是数字,还没有调用前面设计的转换程序!!!!!!
mov ax,0
mov al,es:[bx+6];读收入
mov ds:[bx+20],al;写收入到显存区
mov byte ptr ds:[bx+21],02
mov al,es:[bx+8];第二位
mov ds:[bx+22],al
mov byte ptr ds:[bx+23],02
mov al,es:[bx+10];第三位
mov ds:[bx+24],al
mov byte ptr ds:[bx+25],02;●有个问题:前面那些数位数较少,没读到数会出现什么情况?●
mov al,es:[bx+12];第四位
mov ds:[bx+26],al
mov byte ptr ds:[bx+27],02
mov al,es:[bx+14];第五位
mov ds:[bx+28],al
mov byte ptr ds:[bx+29],02
mov al,es:[bx+16];第六位
mov ds:[bx+30],al
mov byte ptr ds:[bx+31],02
mov al,es:[bx+18];第七位
mov ds:[bx+32],al
;mov byte ptr ds:[bx+33],02;●怪,多此句就汇编失败?!第七位已读出显示白色,难道此位不能改颜色?
;●●●●想先完成年份和收入显示,成功后再增加后两项。●●●●●●●●●●●●
;mov ax,0;●●●●●●●●●●●●怪事!在此增加任何语句都导致汇编失败!!!!是否程序太长越段须far属性?●●●●
;mov al,es:[bx+22];读人数,;用debug u全部列出都在一个段中,那什么原因?
;mov ds:[bx+40],al;写人数到显存区
;mov byte ptr ds:[bx+41],02
;mov al,es:[bx+24];第二位
;mov ds:[bx+42],al
;mov byte ptr ds:[bx+43],02
;mov al,es:[bx+26];第三位
;mov ds:[bx+44],al
;mov byte ptr ds:[bx+45],02
;mov al,es:[bx+28];第四位
;mov ds:[bx+46],al
;mov byte ptr ds:[bx+47],02
;mov al,es:[bx+30];第五位
;mov ds:[bx+48],al
;mov byte ptr ds:[bx+49],02;●●发现此段搬到“call divdw;此段完成人数转字符工作●●●●●”下汇编就可以,见鬼,不知原因!
;难道与选ds做显存有关?
add bx,320;●●●●由160改为360后显出1995 5937000●可见须占领整个屏幕才能正常显示●●●●●●●●●●●●
loop kk
mov ax,4c00h
int 21h
;除法不溢出程序数字转显示字符字程序
divdw proc
mov cx,0ah;这个数是上面公式中的N
mov di,1000;●●要么写10进制mov bx,1000,要么写16进制mov bx,03e8h重点在于h●●
mov bp,0 ;●●跟踪显示上句处于t=0 380位置
cmp dx,0;先看看,若dx=0,则要处理的是小于65536
je qq;小于65536就跳过/1000的处理
div di
;得ax=12345,dx=666,即将12345666/1000分两部分处理
push ax
mov ax,dx
yy:mov ax,ax
mov dx,0
div cx;ax=66,dx=6
add dx,30h
mov es:[si+bx],dx;写到数据区,从右向左写
sub si,2
inc bp
cmp bp,3;不用ax=0作判断,而用是否已写了3次(无论是否是0)作判断!
je xx ;●遇到全0时如何跳出循环?写3个0就跳出写3个0就跳出
jmp yy
;处理12345
xx:pop ax
qq:mov ax,ax
mov dx,0
div cx;ax=66,dx=6
add dx,30h
mov es:[si+bx],dx;写到数据区,从右向左写
sub si,2
cmp ax,0
je qqq
jmp qq
qqq:
ret
divdw endp
code ends
end start