1. 程式人生 > >彙編程式設計:lib庫的使用以及建立函式庫

彙編程式設計: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
在這裡插入圖片描述