彙編程式設計:lib庫的使用以及建立函式庫
阿新 • • 發佈:2019-01-02
下面是閏年程式的程式碼示例:(我將以這個閏年程式演示如何建立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