汇编程序设计:lib库的使用以及建立函数库

下面是闰年程序的代码示例:(我将以这个闰年程序演示如何建立lib函数库)

data segment    ;定义数据段
    infon db 0dh,0ah,'Please input a year: $'	;infon ,双字节,回车换行,内容
    Y db 0dh,0ah,'This is a leap year! $'	;y ,双字节,回车换行,内容
    N db 0dh,0ah,'This is not a leap year! $' 	;n ,双字节,回车换行,内容($是结束符)
    w dw 0		;w为双字类型
    buf db 8		;开辟8个双字节类型的缓冲区,未赋值
        db ?		
        db 8 dup(?)		
data ends

stack segment stack
    db 200 dup(0)	;开辟200个双字节类型的存储空间。(保护现场用到)
stack ends

code segment
          assume ds:data,ss:stack,cs:code
    start:mov ax,data	;寄存器间的数据交换,把data给了数据段
          mov ds,ax
          
          lea dx,infon  ;在屏幕上显示提示信息
          mov ah,9
          int 21h

          lea dx,buf    ;从键盘输入年份字符串
          mov ah,10
          int 21h
          
          mov cl, [buf+1] 	;把buf+1地址指向的内容给cl,buf长度
          lea di,buf+2		;把buf+2的地址给di,buf偏移地址
          call datacate  ;调用函数datacate,传递参数
          call ifyears	;调用函数ifyears,由参数判断是否为闰年
          jc a1			;若产生进位就跳到a1处
          
          lea dx,n		;dx加载n的地址'This is not a leap year!'
          mov ah,9		;显示dx内的内容
          int 21h
          jmp exit		;跳到exit
    a1:   lea dx,y		;dx加载y的地址'This is a leap year!'
          mov ah,9
          int 21h
    exit: mov ah,4ch	;结束本程序,返回 DOS 操作系统
          int 21h
       
 
;实现将字符串的闰年转换为数字存储在ax中
datacate proc near;	;段内调用,子函数1
          push cx;      ;保护现场                                               
          dec cx		
          lea si,buf+2	;把buf+2的地址给si
     tt1: inc si		;移动到字符串指定位置
          loop tt1		;循环函数是个递增函数, loop指令的格式是:loop标号,cpu执行loop指令的时候,要进行两步操作
						;1:(cx)=(cx)-1    
						;2:判断cx中的值,不为零则转至标号处执行,如果为零,则向下执行
          ;lea si,cx[di]
          pop cx		;恢复现场
     
      
          mov dh,30h	
          mov bl,10		;乘数设置为10
          mov ax,1		
      l1: push ax		;保护现场
          sub  byte ptr [si],dh		;没有寄存器参与的内存单元访问指令(DMA),si-dh保存在si中
          mul  byte ptr [si]		;没有寄存器参与的内存单元访问指令(DMA),ax*si,结果放在eax中,这里的寄存器si是16位,被乘数在ax中也是16位。
          							;MUL r/m(寄存器或者内存)  ;mul是字内乘法,把si对应的地址内一个字的长度赋给
									;如果参数是 r8/m8,   将把 AL 做乘数, 结果放在 AX
									;如果参数是 r16/m16, 将把 AX 做乘数, 结果放在 EAX
									;如果参数是 r32/m32, 将把 EAX 做乘数, 结果放在 EDX:EAX
          add w,ax		;w+ax,结果存入w,存入的是数字
          pop ax		;恢复现场
          mul bl		;bl*al,结果存放在ax中
          dec si		;si中的内容减一
          loop l1		;l1循环,cx判断次数
          ret
 datacate endp

;实现ax中年份的判断
   ifyears proc near		;段内调用,子函数2
           push  bx 		;保护现场(保护谁,就用到谁)
           push  cx
           push  dx
           mov ax,w			;把w值赋给cx,w值为
           mov   cx,ax		;把ax值赋给cx
           mov  dx,0		
           mov  bx,4		;ax/4
           div  bx			;ax/bx,结果在ax中,余数在dx中
           					;如果除数是8位,那么除法的结果AL保存商,AH保存余数,
       						;如果除数是16位,那么除法的结果 AX保存商,DX保存余数。
           cmp  dx,0		;比较余数和0,结果存入cf标志位(进位标志位)
           jnz  lab1		;如果非0,跳转到lab1处
           mov   ax,cx		
           mov  bx,100		;ax/100
           div  bx			
           cmp dx,0			;比较余数和0,结果存入cf标志位(进位标志位)
           jnz  lab2		;如果非0,跳到lab2
           mov  ax,cx		
           mov bx,400		;ax/400
           div  bx			
           cmp  dx,0		;比较余数和0,结果存入cf标志位(进位标志位)
           jz  lab2			;cf=0跳到lab2
     lab1: clc				;清除cf标志位,设置cf=0
           jmp lab3			;跳到lab3
     lab2: stc				;cf置1
     lab3: pop  dx			;恢复现场
           pop  cx		
           pop  bx
           ret
   ifyears endp
code ends
   end start

首先要把lib库中的函数分离出来,也就是每个函数成为一个独立的asm文件。
datacate函数部分

extrn infon:byte,y:byte,n:byte,w:word,buf:byte
public datacate
code segment
   assume cs:code
   datacate proc far
          push cx;                                                       
          dec cx
          lea si,buf+2
     tt1: inc si
          loop tt1
          ;lea si,cx[di]
          pop cx

          mov dh,30h
          mov bl,10
          mov ax,1
      l1: push ax
          sub  byte ptr  [si],dh
          mul  byte ptr [si]
          add w,ax
          pop ax
          mul bl
          dec si
          loop l1
          ret
   datacate endp
   code ends
       end

ifyears函数部分

extrn infon:byte,y:byte,n:byte,w:word,buf:byte
public ifyears

code segment
   assume cs:code
   ifyears proc far
           push  bx
           push  cx
           push  dx
           mov ax,w
           mov   cx,ax
           mov  dx,0
           mov  bx,4
           div  bx
           cmp  dx,0
           jnz  lab1
           mov   ax,cx
           mov  bx,100
           div  bx
           cmp dx,0
           jnz  lab2
           mov  ax,cx
           mov bx,400
           div  bx
           cmp  dx,0
           jz  lab2
     lab1: clc
           jmp lab3
     lab2: stc
     lab3: pop  dx
           pop  cx
           pop  bx
           ret
   ifyears endp
   code ends
       end

main主函数部分
注意:库函数中的函数全部为段间调用,所以需要修改函数为far类型。

extrn datacate:far,ifyears:far
public infon,y,n,w,buf

data segment    ;定义数据段
    infon db 0dh,0ah,'Please input a year: $'
    Y db 0dh,0ah,'This is a leap year! $'
    N db 0dh,0ah,'This is not a leap year! $'
    w dw 0
    buf db 8
        db ?
        db 8 dup(?)
data ends

stack segment stack
    db 200 dup(0)
stack ends

code segment
          assume ds:data,ss:stack,cs:code
 start:mov ax,data
          mov ds,ax
          
          lea dx,infon  ;在屏幕上显示提示信息
          mov ah,9
          int 21h

          lea dx,buf    ;从键盘输入年份字符串
          mov ah,10
          int 21h
          
          mov cl, [buf+1]
          lea di,buf+2
          call datacate
          call ifyears
          jc a1
          
          lea dx,n
          mov ah,9
          int 21h
          jmp exit
    a1:   lea dx,y
          mov ah,9
          int 21h
    exit: mov ah,4ch
          int 21h

code ends
     end start

可以看到主函数与子函数之间的参数传递是通过extrn关键字完成的:子函数中没有代码段,主函数中没有子函数的定义。

然后就要用lib.exe生成库函数:(一般在dosbox的bin中)
在这里插入图片描述
lib.exe的使用方法:
Operations:放生成的obj文件(放子函数datacate和ifyears)
List file:要放asm文件(功能一般用不到)
生成lib的步骤:
编译3个asm文件(main,datacate,ifyears),生成obj文件
在这里插入图片描述
在这里插入图片描述
利用lib.exe生成,逐次添加子函数
在这里插入图片描述
masm611的lib.exe生成的静态库是可以扩展的。
在这里插入图片描述
链接时使用main.obj和mylib进行链接操作生成exe
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/hairi1234/article/details/85566345