鱼C论坛

 找回密码
 立即注册
查看: 2981|回复: 4

《王爽汇编》课程设计1,如何编译连接多文件

[复制链接]
发表于 2011-9-24 19:34:12 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 wangkaichao2 于 2011-9-24 20:35 编辑
;;------------------------------------------------------------------------------------------
;;                                王爽汇编课程设计1(第211页)
;;                感谢王爽老师的这本《汇编语言》,让我受益匪浅,尤其是代码段,数据段,栈段的讲解,
;;        太经典了,看了之后已经对这本书爱不释手,以前看过单片机的的汇编,8086的汇编刚学了两
;;        周,下面是我对课程设计1的实现。
;;        求助:
;;        1)我觉得我写的代码很不规范,希望高手在编写规范的和高质量的汇编代码方面给我多提出意见。
;;        2)我不知道如何将汇编的多个子模块分别放在多个*.asm文件里,然后像C语言一样编译连接相互
;;                调用的各个模块文件,希望高手能给出帮助,谢谢
;;                                                                                                                作者:wangkaichao2
;;-----------------------------------------------------------------------------------------
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'
        ;0 + 21 * 4 = 84
        dd 16, 22, 382, 1356, 2390, 8000, 16000, 24486, 50065, 97479, 140417, 197514
        dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000
        ;84 + 21 * 4 = 168
        dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5735, 8226
        dw 11542, 14430, 15257, 17800
        ;168 + 2 * 21 = 210
data ends

table segment
        db 80 dup (0)
table ends

code segment
;;------------------------------------------------------------------------------------
;;                                王爽汇编课程设计1(第211页)
;;                                                MAIN
;;------------------------------------------------------------------------------------
start:
        mov ax, data
        mov es, ax
        mov di, 0
        mov bx, 0

        mov ax, table
        mov ds, ax        ;指定table的段地址
        mov si, 0
        
        mov dh, 3        ;行号
        mov dl, 0        ;列号
        mov cx, 21
next_line:
        push cx                ;循环体中用到cl
        call fill_table
        inc dh                ;行号加1,显示下一行
        mov cl, 2        ;绿色字
        call show_str        ;入参(dh),(dl),(cl),ds:si
        add di, 4        ;如果把data段看作结构体数组,(di)就是结构体数组中“年份”和“总收入”下标
        add bx, 2        ;(bx)是结构体数组中“公司雇员”的下标
        pop cx
        loop next_line
        
        mov ax, 4c00H
        int 21H
;;------------------------------------------------------------------------
                ;;名称:show_str
                ;;功能:在指定位置,用指定的颜色,显示一个用0结束的字符串
                ;;入参:(dh)=行号(0~24),(dl)=列号(0~79),(cl)=颜色,
                ;;                ds:si指向字符串的首地址
                ;;返回值:无
;;------------------------------------------------------------------------
show_str:        ;dh * A0H + dl定位显存偏移起始地址
        push dx
        push ds
        push si

        push ax 
        push bx        ;显存偏移地址
        push es        ;显存段地址
        push cx        ;保存ch中的未知数据

        mov ax, 0b800H
        mov es, ax
        mov ax, 0a0H        ;一行a0H个字节
        mul dh                        ;计算第(dh)行的起始偏移地址
        mov dh, 0                ;清零,只保留dl中的列数
        add ax, dx                ;加上列地址,不行的话改为mov dh, 0;add ax, dx
        add ax, dx                ;一列占两个字节
        mov bx, ax                ;es:bx = 字符串在显存中的起始地址
        mov ah, cl                ;ah存储颜色

        mov ch, 0

showChar:        ;将字符串循环填充到显存
        mov cl, [si]
        jcxz toNull
        mov al, cl                ;al存储ASCII码
        mov es:[bx], ax        ;将ASCII码和属性送入显存
        add bx, 2
        inc si
        jmp short showChar
        
toNull:
        pop cx
        pop es
        pop bx
        pop ax

        pop si
        pop ds
        pop dx
        ret                ;;show_str end

;;-------------------------------------------------------------------------------
;;        名称:dtoc
;;        功能:将dword型数据转变为表示十进制数的字符串,字符串以0为结尾符。
;;        参数:(dx)=dword型高16位
;;                  (ax)=dword型低16位
;;                  ds:si指向字符串首地址
;;        返回:无
;;        应用举例:将12666以十进制形式在屏幕的8行3列,用绿色显示
;;        该子模块调用了show_str, divdw子程序段
;;-------------------------------------------------------------------------------
dtoc:
        push dx
        push ax
        push ds
        push cx

        push si

next_div:
        mov cx, 10
        call divdw        ;商(dx)(ax),余数(cx)
        add cx, 30H
        mov [si], cl        ;ASCII占一个字节
        inc si
        ;;判断(ax)是否等于0
        mov cx, ax
        add cx, 1                ;cx先增1,改成 inc cx ?
        loop next_div        ;cx先减1,if(cx != 0),商不为0
        ;;在(ax)等于0的前提下,判断(dx)是否等于0
        mov cx, dx
        jcxz div_end        ;if(dx==0),商为0,循环结束
        loop next_div

div_end:
        mov byte ptr [si], 0        ;字符串0结束符
        pop si                                        ;ds:si=字符串起始地址
        call str_reserve                ;颠倒字符串

        pop cx
        pop ds
        pop ax
        pop dx
        ret                                ;;dtoc子程序结束

;;--------------------------------------------------------------------------------------
;;        名称:divdw
;;        功能:进行不会产生溢出的除法运算,被除数dword型,除数word型
;;        入参:(dx) = 被除数高16位,(ax)= 被除数第16位,(cx) = 除数
;;        返回值:(dx) = 商高16位,(ax) = 商第16位,(cx) = 余数
;;                        余数为word型,结果为dword型
;;        int():描述性运算符,取商,比如,int(38/10)=3
;;        rem():描述性运算符,取余,比如,rem(38/10)=8
;;        X:被除数,N:除数
;;        公式:X/N = int(H/N)*10000H + [rem(H/N)*10000H + L]/N
;;--------------------------------------------------------------------------------------
divdw:
        push bx
        push ax                ;被除数低16位入栈
        mov ax, dx        ;处理高16被除数
        mov dx, 0
        div        cx                ;int(H/N)*10000H
        mov bx, ax        ;bx暂存高16位除后的商
        pop ax                ;获取被除数低16位
        div cx                ;[rem(H/N)*10000H + L]/N
        mov cx, dx        ;cx存放余数
        mov dx, bx        

        pop bx
        ret                        ;;end divdw

;;-------------------------------------------------------------------------------------
;;        名称:str_reserve
;;        功能:将数据段中的以0结尾字符串逆序排列
;;        参数:ds:si = 字符串首地址
;;        返回值:(cx) = 字符串长度
;;        该子模块调用了get_str_length
;;-------------------------------------------------------------------------------------
str_reserve:        
        push ds
        push si                ;字符串前后交换时,(si)从第一个字符开始向中间移动
        push di                ;字符串前后交换时,(di)从最后一个字符开始向中间移动
        push ax                ;除法操作
        call get_str_length        ;字符串长度在(cx)中
        push cx                ;将字符长度入栈

        mov di, si
        add di, cx
        dec di                ;(di)=最后一个字符的下标

        mov ax, cx
        mov cl, 2
        div cl                ;该8位除法只针对长度小于512的字符串,>=512产生除法溢出
        mov ah, 0
        add ax, si        ;;(ax)=字符中间下标,

next_char_reserve:
        mov cx, ax        ;(ax)是字符串中间下标
        sub cx, si        ;if(cx == 0),字符串逆序完成
        jcxz str_reserve_end
        ;;交换前后字符
        mov cl, [si]
        mov ch, [di]
        mov [di], cl
        mov [si], ch
        dec di
        inc si
        jmp next_char_reserve

str_reserve_end:
        pop cx                ;字符创长度出栈

        pop ax
        pop di
        pop si
        pop ds
        ret                        ;end str_reserve
;;-------------------------------------------------------------------------------------
;;        名称:get_str_length
;;        功能:获取一个以0结束的字符串的长度
;;        入参:ds:si = 字符串首地址
;;        返回值:(cx) = 字符串长度
;;-------------------------------------------------------------------------------------
get_str_length:        ;返回值(cx)
        push ds
        push si
        mov cx, 0
next_char:
        mov cl, [si]
        jcxz str_end
        inc si
        jmp short next_char
str_end:
        mov cx, si
        pop si
        pop ds
        sub cx, si        ;(cx)-(si)的值就是字符串长度
        ret                        ;end get_str_length

;;----------------------------------------------------------------------------------
;;        名称:fill_table
;;        功能:将data段(结构体数组)中的所有字段,转换成以零结束的字符串,存储到table段中,
;;        格式如下:
;;                        0123456789012345678901234567890123456789|
;;                        1975      16        3         5         |结束符
;;        入参:ds:si = table段首地址,es:di = ,es:bx
;;        补充说明:        es:[di].0 = data中某一年份(4个byte)首地址
;;                                es:[di].84 = data中某一年份总收入(dword)首地址
;;                                es:[bx].168 = data中某一年份公司雇员(dw)字段首地址
;;        返回值:无
;;        该子模块调用了fill_blank,get_str_length,dtoc
;;----------------------------------------------------------------------------------
fill_table:
        push es
        push di                ;;(es):(di) = data中的数据
        push bx                ;;(es):(bx) = data中的数据

        push ds
        push si                ;;(ds):(si) = table中的数据

        push cx                ;;控制各种循环及jcxp指令等

        push ax        
        push dx                ;;除法操作入参

;;填充年份
        mov cx, 4
        push di
s0:
        mov al, es:[di]
        mov [si], al
        inc di
        inc si
        loop s0
        pop di

;;填充空格
        mov cx, 10        ;;cx绝对下标
        call fill_blank        ;入参(cx), ds:si
        mov si, cx                ;ds:si = 空格后(收入)字符串起始地址
;;填充公司收入        (si)=10H
        mov ax, es:[di+0].84
        mov dx, es:[di+2].84
        call dtoc
        call get_str_length        ;(cx)=收入字符串长度
        add si, cx                        ;ds:si=收入字符串0结束符地址
;;填充空格
        mov cx, 20
        call fill_blank
        mov si, cx
s4:        ;;填充雇员数 2字节
        mov ax, es:168[bx]        ;入参
        mov dx, 0                        ;入参
        call dtoc
        call get_str_length
        add si, cx
;;填充空格,上面入栈的(di)没有出栈是因为计算人均收入时还要用到现在减半的(di)
        mov cx, 30
        call fill_blank
        mov si, cx
;;填充人均收入
        mov cx, es:168[bx]        ;入参,这里的(di)是减半后的(di)
        mov ax, es:84[di]        ;入参
        mov dx, es:84[di+2]        ;入参
        call divdw

        call dtoc
        call get_str_length
        add si, cx
;;填充空格
        mov cx, 40
        call fill_blank
        mov si, cx
;;填充字符串结束符
        mov byte ptr [si], 0
;;end
        pop dx
        pop ax

        pop cx

        pop si
        pop ds

        pop bx
        pop di
        pop es
        ret                ;;end fill table
;;--------------------------------------------------------------------------------------
;;名称:fill_blank
;;功能:将指定的一段偏移内存填充为空格字符
;;入参:ds:si = 填充空格起始下标,(cx) = 填充空格截止下标,该字节不会被空格填充
;;返回值:无
;;--------------------------------------------------------------------------------------
fill_blank:                ;;入参(cx)=填充空格截止下标,ds:si = 填充空格起始下标
        push ds
        push si
        push bx

fill_next_blank:
        push cx                ;填充空格截止下标入栈
        sub cx, si
        jcxz fill_blank_end        ;(cx)==0时,栈顶为(cx)
        mov bl, 20H
        mov [si], bl
        inc si
        pop cx                ;填充空格截止下标出栈
        jmp fill_next_blank

fill_blank_end:
        pop cx

        pop bx
        pop si
        pop ds
        ret                ;;end fill_blank
;;-------------------------------------------------------------------------------------
code ends
end start
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-9-26 01:02:56 | 显示全部楼层
本帖最后由 flyue 于 2011-9-26 20:41 编辑

    assume cs:code,ss:ss1,ds:data
    data segment
    db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
    db '1984','1985','1986','1987','1988','1989','1990','1991','1982'
    db '1993','1994','1995'
    dd 16,22,382,1356,2390,8000,16000,24486,50065,97497,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  
    data ends
    ss1 segment
    db 64 dup(0)
    ss1 ends
    code segment
    start:mov ax,data
          mov es,ax
       mov ax,ss1
       mov ss,ax
       mov dh,3
       mov dl,3
          mov bx,0
       mov di,0
       mov cx,21
    pr:call show_str
       push dx
          mov ax,es:[bx+80]              ;将DWORD中的第一个数据低位送入AX
       mov dx,es:[bx+82]              ;将DWORD中的第一个数据高位送入DX
       add si,40                      ;将数据位置后移20位
       call dtoc       
       mov ax,es:[di+168]             ;将WORD中的第一个数据送入AX中      
       mov dx,0
       add si,40                      ;将数据位置后移20位
       call dtoc
       push cx
      mov ax,es:[bx+80]               
      mov dx,es:[bx+82]
      mov cx,es:[di+168]
      call divdw 
      add si,40                        ;将数据位置后移20位
      call dtoc
      pop cx
      pop dx
      add dh,1                         ;进入数据的下一行位置
      add di,2
         loop pr
      mov ax,4c00h
      int 21h
       
    dtoc:push si                         ;SI入栈,保存SI值 
         push cx                         ;CX入栈,保存CX值
      push dx                         ;DX入栈,保存DX值
      push bx                         ;BX入栈,保存BX值
      mov bx,0                        ;计算当前DWORD型数据的位数,设置其为0
       s:mov cx,10                       ;除数为10,S段开始
           call divdw                    ;调用除法溢出处理子程序
          push cx                        ;保存余数CX
       inc bx                         ;DWORD型数据位数自加1
       mov cx,ax
       jcxz s1                        ;当最后一位余数是0时跳转至S1
       jmp short s                    ;跳转至S
    s1:pop cx                        ;取出CX值,S1段开始
        dec bx                        ;DWORD型数据位数自减1
        add cl,30h                    ;将CX值转换为ASCII码
        mov ds:[si],cl                ;将CX值送入数据段当前地址SI中  
        mov dl,1                      ;将颜色值送入DX
        mov ds:[si+1],dl              ;;将颜色送入当前地址SI后一位地址中
        add si,2                        ;数据地址自加2
        mov cx,bx                     ;将当前BX值送入CX中,DWORD型数据位数
        jcxz s2                       ;当DWORD型数据位数为0时,跳转至S2
        jmp short s1                  ;跳转至S1
    s2:pop bx                        ;取出BX值
        pop dx                        ;取出DX值
        pop cx                        ;取出CX值
        pop si                        ;取出SI值
        ret 
    divdw:push bx                        ;BX入栈,保存BX值
           push ax                       ;DWORD型数据低16位AX入栈
           mov ax,dx                     ;将DWORD型数据高16为AX中
           mov dx,0                      ;将DX值写入0
        div cx                        ;DWORD数据除以CX
        mov bx,ax                     ;结果商送入BX中
        pop ax                        ;取出DWORD型数据低16位AX中
        div cx                        ;以余数DX为高16位CX,除以CX
           mov cx,dx                     ;将余数送入CX
        mov dx,bx                     ;将结果商高16位送入DX中
        pop bx                        ;BX出栈,还原BX值
        ret                           ;返回
    show_str:push dx
             push cx
       push ax                     ;AX入栈,保存AX值
       mov si,0                    ;将数据指向数据段0位置
            mov ah,dh                    ;将数据行数送入AH
             mov al,160                  ;将一行总字节数送入AL
             mul ah                      ;进行AH八位乘法,得到数据送入行数的首位地址
       mov dh,0                    ;将DX高位清零,得到数据列偏移大小
             add ax,dx                   
       add ax,dx                   
       add si,ax                   ;数据首位地址加列偏移大小得到数据写入位置
       mov ax,0b800h               
       mov ds,ax                   ;送入数据段段地址
           mov cx,4         
          l: mov dl,01
         mov al,es:[bx]               ;将文本数据的首个字符送入AL中
       mov ds:[si],al              ;将AL中数据送入当前数据写入地址
       mov byte ptr ds:[si+1],dl   ;将文字颜色写入数据写入地址后一位地址中
       inc bx                      ;文本数据地址自加一
       add si,2                    ;数据写入地址自加2
       loop l                      ;跳转至l
    ok: pop ax                       ;AX出栈,取回AX值
            pop cx
      pop dx
         
          ret                         ;返回
    code ends 
    end start
    
    
    我刚看完10章写的,我们讨论讨论?还有就是我怎么和你一样的把程序发上来啊,我只会这样的复制发上来。不方便观看哦。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2011-9-26 16:33:23 | 显示全部楼层
工具栏里有个“代码”按钮,图标是“<>”,把代码复制进去就行了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-9-29 02:11:44 | 显示全部楼层
你说如何编译连接多个文件,其实不是不就是用INT中断来完成的,这个和那个原理上来说应该是一样的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-10-1 00:42:51 | 显示全部楼层
没看完~~~~~~ 先顶,好同志
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-10-8 22:10

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表