首页
社区
课程
招聘
[旧帖] [原创]王爽《汇编语言第二版》第10章 课程设计1 0.00雪花
2012-6-4 10:26 1899

[旧帖] [原创]王爽《汇编语言第二版》第10章 课程设计1 0.00雪花

2012-6-4 10:26
1899
本章还有一个实验10 编写子程序。但是本课程设计包括了写的子程序的所有内容,在代码中也包含所有写的子程序的代码,所以直接看本课程设计的代码就可以了。

在前面的学习中,有一个实验是将poweridea公司的数据按格式写到一个table段中,而本课程设计是要求就数据写到显存以显示在屏幕上,所以我们可以在以前的程序基础上修改,比如可以保留以前的程序,先写到table表,然后从table表读到显存。不过我这里的实现是去掉这些不必要的消耗,也删掉了table表,使程序更高效。另外,在code段里面还有几个子程序,代码的关键部分也都做了注释,实现如下:
DATAS 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 11542,14430,15257,17800
    
    ;起始行:4
    db 4
    ;各字段的列:year=8;收入=16;雇员=30;平均收入=42
    db 8,16,30,42
    ;字符缓冲区
    db 20 dup (0)
DATAS ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
    dw 20 dup (0)
STACKS ENDS


CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
    MOV AX,DATAS
    MOV DS,AX
    mov ax,STACKS
    mov ss,ax
    mov sp,40
     
    mov bp,215  
    
    mov si,0 ;for year and summ
    mov di,0 ;for ne
    mov cx,21
   
    show:
    push cx    
    mov cl,0f2h ;颜色
    
    ;year 偏移0
    mov ax,[si]
    mov ds:[bp].0,ax
    mov ax,[si+2]
    mov ds:[bp].2,ax
    mov ds:[bp].4,0
    
    push si
   push dx
    mov si,bp
    mov dh,ds:[210]
    mov dl,ds:[211] ;列号
    call show_str
    pop dx
    pop si        
    
    ;收入summ 偏移5
    mov ax,84[si]
    mov dx,84[si+2]
    
    push ax
    push dx
    push si
    mov si,bp
    call ddtoc
    mov dh,ds:[210]
    mov dl,ds:[212] ;列号
    call show_str    
    pop si   
    pop dx
    pop ax
    
    add si,4
    
    ;雇员数ne 偏移10
    mov bx,168[di]
    add di,2    
    
    push ax
    push dx
    push si
    mov ax,bx
    mov si,bp
    call dtoc
    mov dh,ds:[210]
    mov dl,ds:[213] ;列号
    call show_str
    pop si   
    pop dx
    pop ax  
    
    ;人均收入 偏移13
   div bx
   
    push ax
    push dx
    push si
    mov si,bp
    call dtoc
    mov dh,ds:[210]
    mov dl,ds:[214] ;列号
    call show_str
    pop si   
    pop dx
    pop ax  
    
    mov cl,ds:[210]
    inc cl
    mov ds:[210],cl
    pop cx

    ;loop show  ;报错:jump destination too far ,所以自己手动判断cx来跳转。
    dec cx
    jcxz finish
    jmp show
    
    finish:
    mov ah,4CH
    int 21H
    
    ;名称:show_str
  ;功能:在指定位置,用指定的颜色,显示一个用0结束的字符串
  ;参数:(dh)=行号,(dl)=列号,(cl)=颜色,ds:si指向字符串的首地址
  show_str:
    push ax
    push cx
    push dx    
    push es        
    push si
    push di
        
    ;根据行号设置基址为bp
    mov ax,160
    mul dh
    mov bp,ax
    ;根据列号设置基址为di
    mov dh,0
    add dx,dx  ;没个字符对应2个字节,所以列号*2
    mov di,dx   
    ;显存段地址
    mov ax,0b800h
    mov es,ax      
    ;保存颜色属性到al中
    mov al,cl
    
    sub cx,cx
    showstr:
    mov cl,[si] ;取字符
    jcxz ok
    mov es:[bp+di],cl  ;写字符
    mov es:[bp+di].1,al ;设置颜色属性
    add di,2
    inc si
    loop showstr
    ok:
    pop di
    pop si
    pop es
    pop dx
    pop cx
    pop ax
 
    ret
    
    ;divdw
    ;功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型
    ;参数:ax=dword型数据的低16位,dx=dword型数据的高16位,cx=除数
    ;返回:dx=结果的高16位,ax=结果的低16位,cx=余数
    divdw:
    push bx  ;以后恢复

    push ax
    mov ax,dx
    sub dx,dx
    div cx
    mov bx,ax ;bx=int(H/N)
    pop ax
    div cx
    mov cx,dx
    mov dx,bx
    pop bx ;恢复bx
    ret
    
    ;dtoc
    ;功能:将word型数据转变为表示十进制的字符串,字符串以0为结束符
    ;参数:ax=word型数据;ds:si指向字符串的首地址
    ;返回:无
    dtoc:
    push ax
    push bx
    push cx
    push dx   
    push si 
    
    ;先插入数据结束标记0
    sub dx,dx
    push dx    
    mov bx,10
    s1:    
    div bx
    add dx,30h  ;转为ASCII码
    push dx
    mov cx,ax
    jcxz ok1
    sub dx,dx
    jmp s1
    
    ok1:
    pop cx
    jcxz ok2
    mov [si],cl
    inc si
    jmp ok1
    
    ok2:
    ;给字符串后面添0
    mov [si],cl
    
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    ret
    
    ;ddtoc
    ;功能:将dword型数据转变为表示十进制的字符串,字符串以0为结束符
    ;参数:ax=dword型数据的低16位;dx=dword型数据的高16位;ds:si指向字符串的首地址
    ;返回:无
    ddtoc:
    push ax
    ;push bx
    push cx
    push dx   
    push si 
    
    ;先插入数据结束标记0
    sub cx,cx
    push cx        
    dd10:    
    mov cx,10
    call divdw
    add cx,30h  ;转为ASCII码
    push cx
    mov cx,ax
    jcxz testhigh
    jmp dd10
    
    testhigh:
    mov cx,dx
    jcxz geascii
    jmp dd10
    
    geascii:
    pop cx
    jcxz win
    mov [si],cl
    inc si
    jmp geascii
    
    win:
    ;给字符串后面添0
    mov [si],cl
    
    pop si
    pop dx
    pop cx
    ;pop bx
    pop ax
    ret
CODES ENDS
    END START

运行结果如下:


总结:

1、程序实现中基本都用到了栈,主要用于暂存寄存器数据。不过在子程序dtoc和ddtoc中,我还用栈存放参数%10的值,因为形成字符串时需要逆序写到内存。

2、在dtoc和ddtoc中,为了区分保存的寄存器数据和十进制数的ascii值,特意往栈中压入一个0,作为“桩”。

3、主程序中在循环跳转的loop语句被注释掉:“;loop show ;报错:jump destination too far ,所以自己手动判断cx来跳转。”,原因正如说明,偏移超过了一个字节,所以我自己修改判断cx而利用jmp(jmp near)来实现跳转。因为所有有条件跳转都是短转移,是不是把循环中间的一些内容也写到子程序来减少偏移更好?

4、对显示时的起始行和列偏移的数据,我都统一放在数据段中,可以很方便的修改来查看效果。

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

上传的附件:
收藏
点赞3
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回