鱼C论坛

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

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

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

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

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

x
本帖最后由 wangkaichao2 于 2011-9-24 20:35 编辑


  1. ;;------------------------------------------------------------------------------------------
  2. ;;                                王爽汇编课程设计1(第211页)
  3. ;;                感谢王爽老师的这本《汇编语言》,让我受益匪浅,尤其是代码段,数据段,栈段的讲解,
  4. ;;        太经典了,看了之后已经对这本书爱不释手,以前看过单片机的的汇编,8086的汇编刚学了两
  5. ;;        周,下面是我对课程设计1的实现。
  6. ;;        求助:
  7. ;;        1)我觉得我写的代码很不规范,希望高手在编写规范的和高质量的汇编代码方面给我多提出意见。
  8. ;;        2)我不知道如何将汇编的多个子模块分别放在多个*.asm文件里,然后像C语言一样编译连接相互
  9. ;;                调用的各个模块文件,希望高手能给出帮助,谢谢
  10. ;;                                                                                                                作者:wangkaichao2
  11. ;;-----------------------------------------------------------------------------------------
  12. assume cs:code
  13. data segment
  14.         db '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983'
  15.         db '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992'
  16.         db '1993', '1994', '1995'
  17.         ;0 + 21 * 4 = 84
  18.         dd 16, 22, 382, 1356, 2390, 8000, 16000, 24486, 50065, 97479, 140417, 197514
  19.         dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000
  20.         ;84 + 21 * 4 = 168
  21.         dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5735, 8226
  22.         dw 11542, 14430, 15257, 17800
  23.         ;168 + 2 * 21 = 210
  24. data ends

  25. table segment
  26.         db 80 dup (0)
  27. table ends

  28. code segment
  29. ;;------------------------------------------------------------------------------------
  30. ;;                                王爽汇编课程设计1(第211页)
  31. ;;                                                MAIN
  32. ;;------------------------------------------------------------------------------------
  33. start:
  34.         mov ax, data
  35.         mov es, ax
  36.         mov di, 0
  37.         mov bx, 0

  38.         mov ax, table
  39.         mov ds, ax        ;指定table的段地址
  40.         mov si, 0
  41.         
  42.         mov dh, 3        ;行号
  43.         mov dl, 0        ;列号
  44.         mov cx, 21
  45. next_line:
  46.         push cx                ;循环体中用到cl
  47.         call fill_table
  48.         inc dh                ;行号加1,显示下一行
  49.         mov cl, 2        ;绿色字
  50.         call show_str        ;入参(dh),(dl),(cl),ds:si
  51.         add di, 4        ;如果把data段看作结构体数组,(di)就是结构体数组中“年份”和“总收入”下标
  52.         add bx, 2        ;(bx)是结构体数组中“公司雇员”的下标
  53.         pop cx
  54.         loop next_line
  55.         
  56.         mov ax, 4c00H
  57.         int 21H
  58. ;;------------------------------------------------------------------------
  59.                 ;;名称:show_str
  60.                 ;;功能:在指定位置,用指定的颜色,显示一个用0结束的字符串
  61.                 ;;入参:(dh)=行号(0~24),(dl)=列号(0~79),(cl)=颜色,
  62.                 ;;                ds:si指向字符串的首地址
  63.                 ;;返回值:无
  64. ;;------------------------------------------------------------------------
  65. show_str:        ;dh * A0H + dl定位显存偏移起始地址
  66.         push dx
  67.         push ds
  68.         push si

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

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

  82.         mov ch, 0

  83. showChar:        ;将字符串循环填充到显存
  84.         mov cl, [si]
  85.         jcxz toNull
  86.         mov al, cl                ;al存储ASCII码
  87.         mov es:[bx], ax        ;将ASCII码和属性送入显存
  88.         add bx, 2
  89.         inc si
  90.         jmp short showChar
  91.         
  92. toNull:
  93.         pop cx
  94.         pop es
  95.         pop bx
  96.         pop ax

  97.         pop si
  98.         pop ds
  99.         pop dx
  100.         ret                ;;show_str end

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

  116.         push si

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

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

  135.         pop cx
  136.         pop ds
  137.         pop ax
  138.         pop dx
  139.         ret                                ;;dtoc子程序结束

  140. ;;--------------------------------------------------------------------------------------
  141. ;;        名称:divdw
  142. ;;        功能:进行不会产生溢出的除法运算,被除数dword型,除数word型
  143. ;;        入参:(dx) = 被除数高16位,(ax)= 被除数第16位,(cx) = 除数
  144. ;;        返回值:(dx) = 商高16位,(ax) = 商第16位,(cx) = 余数
  145. ;;                        余数为word型,结果为dword型
  146. ;;        int():描述性运算符,取商,比如,int(38/10)=3
  147. ;;        rem():描述性运算符,取余,比如,rem(38/10)=8
  148. ;;        X:被除数,N:除数
  149. ;;        公式:X/N = int(H/N)*10000H + [rem(H/N)*10000H + L]/N
  150. ;;--------------------------------------------------------------------------------------
  151. divdw:
  152.         push bx
  153.         push ax                ;被除数低16位入栈
  154.         mov ax, dx        ;处理高16被除数
  155.         mov dx, 0
  156.         div        cx                ;int(H/N)*10000H
  157.         mov bx, ax        ;bx暂存高16位除后的商
  158.         pop ax                ;获取被除数低16位
  159.         div cx                ;[rem(H/N)*10000H + L]/N
  160.         mov cx, dx        ;cx存放余数
  161.         mov dx, bx        

  162.         pop bx
  163.         ret                        ;;end divdw

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

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

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

  186. next_char_reserve:
  187.         mov cx, ax        ;(ax)是字符串中间下标
  188.         sub cx, si        ;if(cx == 0),字符串逆序完成
  189.         jcxz str_reserve_end
  190.         ;;交换前后字符
  191.         mov cl, [si]
  192.         mov ch, [di]
  193.         mov [di], cl
  194.         mov [si], ch
  195.         dec di
  196.         inc si
  197.         jmp next_char_reserve

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

  200.         pop ax
  201.         pop di
  202.         pop si
  203.         pop ds
  204.         ret                        ;end str_reserve
  205. ;;-------------------------------------------------------------------------------------
  206. ;;        名称:get_str_length
  207. ;;        功能:获取一个以0结束的字符串的长度
  208. ;;        入参:ds:si = 字符串首地址
  209. ;;        返回值:(cx) = 字符串长度
  210. ;;-------------------------------------------------------------------------------------
  211. get_str_length:        ;返回值(cx)
  212.         push ds
  213.         push si
  214.         mov cx, 0
  215. next_char:
  216.         mov cl, [si]
  217.         jcxz str_end
  218.         inc si
  219.         jmp short next_char
  220. str_end:
  221.         mov cx, si
  222.         pop si
  223.         pop ds
  224.         sub cx, si        ;(cx)-(si)的值就是字符串长度
  225.         ret                        ;end get_str_length

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

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

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

  246.         push ax        
  247.         push dx                ;;除法操作入参

  248. ;;填充年份
  249.         mov cx, 4
  250.         push di
  251. s0:
  252.         mov al, es:[di]
  253.         mov [si], al
  254.         inc di
  255.         inc si
  256.         loop s0
  257.         pop di

  258. ;;填充空格
  259.         mov cx, 10        ;;cx绝对下标
  260.         call fill_blank        ;入参(cx), ds:si
  261.         mov si, cx                ;ds:si = 空格后(收入)字符串起始地址
  262. ;;填充公司收入        (si)=10H
  263.         mov ax, es:[di+0].84
  264.         mov dx, es:[di+2].84
  265.         call dtoc
  266.         call get_str_length        ;(cx)=收入字符串长度
  267.         add si, cx                        ;ds:si=收入字符串0结束符地址
  268. ;;填充空格
  269.         mov cx, 20
  270.         call fill_blank
  271.         mov si, cx
  272. s4:        ;;填充雇员数 2字节
  273.         mov ax, es:168[bx]        ;入参
  274.         mov dx, 0                        ;入参
  275.         call dtoc
  276.         call get_str_length
  277.         add si, cx
  278. ;;填充空格,上面入栈的(di)没有出栈是因为计算人均收入时还要用到现在减半的(di)
  279.         mov cx, 30
  280.         call fill_blank
  281.         mov si, cx
  282. ;;填充人均收入
  283.         mov cx, es:168[bx]        ;入参,这里的(di)是减半后的(di)
  284.         mov ax, es:84[di]        ;入参
  285.         mov dx, es:84[di+2]        ;入参
  286.         call divdw

  287.         call dtoc
  288.         call get_str_length
  289.         add si, cx
  290. ;;填充空格
  291.         mov cx, 40
  292.         call fill_blank
  293.         mov si, cx
  294. ;;填充字符串结束符
  295.         mov byte ptr [si], 0
  296. ;;end
  297.         pop dx
  298.         pop ax

  299.         pop cx

  300.         pop si
  301.         pop ds

  302.         pop bx
  303.         pop di
  304.         pop es
  305.         ret                ;;end fill table
  306. ;;--------------------------------------------------------------------------------------
  307. ;;名称:fill_blank
  308. ;;功能:将指定的一段偏移内存填充为空格字符
  309. ;;入参:ds:si = 填充空格起始下标,(cx) = 填充空格截止下标,该字节不会被空格填充
  310. ;;返回值:无
  311. ;;--------------------------------------------------------------------------------------
  312. fill_blank:                ;;入参(cx)=填充空格截止下标,ds:si = 填充空格起始下标
  313.         push ds
  314.         push si
  315.         push bx

  316. fill_next_blank:
  317.         push cx                ;填充空格截止下标入栈
  318.         sub cx, si
  319.         jcxz fill_blank_end        ;(cx)==0时,栈顶为(cx)
  320.         mov bl, 20H
  321.         mov [si], bl
  322.         inc si
  323.         pop cx                ;填充空格截止下标出栈
  324.         jmp fill_next_blank

  325. fill_blank_end:
  326.         pop cx

  327.         pop bx
  328.         pop si
  329.         pop ds
  330.         ret                ;;end fill_blank
  331. ;;-------------------------------------------------------------------------------------
  332. code ends
  333. end start
复制代码

小甲鱼最新课程 -> https://ilovefishc.com
发表于 2011-9-26 01:02:56 | 显示全部楼层
本帖最后由 flyue 于 2011-9-26 20:41 编辑





    1. assume cs:code,ss:ss1,ds:data
    2. data segment
    3. db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
    4. db '1984','1985','1986','1987','1988','1989','1990','1991','1982'
    5. db '1993','1994','1995'
    6. dd 16,22,382,1356,2390,8000,16000,24486,50065,97497,140417,197514
    7. dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
    8. dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
    9. dw 11542,14430,15257,17800  
    10. data ends
    11. ss1 segment
    12. db 64 dup(0)
    13. ss1 ends
    14. code segment
    15. start:mov ax,data
    16.       mov es,ax
    17.    mov ax,ss1
    18.    mov ss,ax
    19.    mov dh,3
    20.    mov dl,3
    21.       mov bx,0
    22.    mov di,0
    23.    mov cx,21
    24. pr:call show_str
    25.    push dx
    26.       mov ax,es:[bx+80]              ;将DWORD中的第一个数据低位送入AX
    27.    mov dx,es:[bx+82]              ;将DWORD中的第一个数据高位送入DX
    28.    add si,40                      ;将数据位置后移20位
    29.    call dtoc      
    30.    mov ax,es:[di+168]             ;将WORD中的第一个数据送入AX中      
    31.    mov dx,0
    32.    add si,40                      ;将数据位置后移20位
    33.    call dtoc
    34.    push cx
    35.   mov ax,es:[bx+80]               
    36.   mov dx,es:[bx+82]
    37.   mov cx,es:[di+168]
    38.   call divdw
    39.   add si,40                        ;将数据位置后移20位
    40.   call dtoc
    41.   pop cx
    42.   pop dx
    43.   add dh,1                         ;进入数据的下一行位置
    44.   add di,2
    45.      loop pr
    46.   mov ax,4c00h
    47.   int 21h
    48.    
    49. dtoc:push si                         ;SI入栈,保存SI值
    50.      push cx                         ;CX入栈,保存CX值
    51.   push dx                         ;DX入栈,保存DX值
    52.   push bx                         ;BX入栈,保存BX值
    53.   mov bx,0                        ;计算当前DWORD型数据的位数,设置其为0
    54.    s:mov cx,10                       ;除数为10,S段开始
    55.        call divdw                    ;调用除法溢出处理子程序
    56.       push cx                        ;保存余数CX
    57.    inc bx                         ;DWORD型数据位数自加1
    58.    mov cx,ax
    59.    jcxz s1                        ;当最后一位余数是0时跳转至S1
    60.    jmp short s                    ;跳转至S
    61. s1:pop cx                        ;取出CX值,S1段开始
    62.     dec bx                        ;DWORD型数据位数自减1
    63.     add cl,30h                    ;将CX值转换为ASCII码
    64.     mov ds:[si],cl                ;将CX值送入数据段当前地址SI中  
    65.     mov dl,1                      ;将颜色值送入DX
    66.     mov ds:[si+1],dl              ;;将颜色送入当前地址SI后一位地址中
    67.     add si,2                        ;数据地址自加2
    68.     mov cx,bx                     ;将当前BX值送入CX中,DWORD型数据位数
    69.     jcxz s2                       ;当DWORD型数据位数为0时,跳转至S2
    70.     jmp short s1                  ;跳转至S1
    71. s2:pop bx                        ;取出BX值
    72.     pop dx                        ;取出DX值
    73.     pop cx                        ;取出CX值
    74.     pop si                        ;取出SI值
    75.     ret
    76. divdw:push bx                        ;BX入栈,保存BX值
    77.        push ax                       ;DWORD型数据低16位AX入栈
    78.        mov ax,dx                     ;将DWORD型数据高16为AX中
    79.        mov dx,0                      ;将DX值写入0
    80.     div cx                        ;DWORD数据除以CX
    81.     mov bx,ax                     ;结果商送入BX中
    82.     pop ax                        ;取出DWORD型数据低16位AX中
    83.     div cx                        ;以余数DX为高16位CX,除以CX
    84.        mov cx,dx                     ;将余数送入CX
    85.     mov dx,bx                     ;将结果商高16位送入DX中
    86.     pop bx                        ;BX出栈,还原BX值
    87.     ret                           ;返回
    88. show_str:push dx
    89.          push cx
    90.    push ax                     ;AX入栈,保存AX值
    91.    mov si,0                    ;将数据指向数据段0位置
    92.         mov ah,dh                    ;将数据行数送入AH
    93.          mov al,160                  ;将一行总字节数送入AL
    94.          mul ah                      ;进行AH八位乘法,得到数据送入行数的首位地址
    95.    mov dh,0                    ;将DX高位清零,得到数据列偏移大小
    96.          add ax,dx                  
    97.    add ax,dx                  
    98.    add si,ax                   ;数据首位地址加列偏移大小得到数据写入位置
    99.    mov ax,0b800h               
    100.    mov ds,ax                   ;送入数据段段地址
    101.        mov cx,4         
    102.       l: mov dl,01
    103.      mov al,es:[bx]               ;将文本数据的首个字符送入AL中
    104.    mov ds:[si],al              ;将AL中数据送入当前数据写入地址
    105.    mov byte ptr ds:[si+1],dl   ;将文字颜色写入数据写入地址后一位地址中
    106.    inc bx                      ;文本数据地址自加一
    107.    add si,2                    ;数据写入地址自加2
    108.    loop l                      ;跳转至l
    109. ok: pop ax                       ;AX出栈,取回AX值
    110.         pop cx
    111.   pop dx
    112.      
    113.       ret                         ;返回
    114. code ends
    115. end start


    116. 我刚看完10章写的,我们讨论讨论?还有就是我怎么和你一样的把程序发上来啊,我只会这样的复制发上来。不方便观看哦。

    复制代码

小甲鱼最新课程 -> https://ilovefishc.com
 楼主| 发表于 2011-9-26 16:33:23 | 显示全部楼层
工具栏里有个“代码”按钮,图标是“<>”,把代码复制进去就行了。
小甲鱼最新课程 -> https://ilovefishc.com
发表于 2011-9-29 02:11:44 | 显示全部楼层
你说如何编译连接多个文件,其实不是不就是用INT中断来完成的,这个和那个原理上来说应该是一样的。
小甲鱼最新课程 -> https://ilovefishc.com
发表于 2011-10-1 00:42:51 | 显示全部楼层
没看完~~~~~~ 先顶,好同志
小甲鱼最新课程 -> https://ilovefishc.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2025-4-22 09:32

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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