組合語言是各種電腦語言中與硬體關係最為密切、最直接的語言,是時空效率最高的語言,它能夠利用電腦所有硬體特性並能直接控制硬體,所以在電腦應用系統設計和過程式控制制中是必不可少的.目前教學中採用8086/8088組合語言系統組織教學仍是最佳選擇.其中子程式技術是一種解決重複性問題的重要設計方法,採用子程式結構可以簡化來源程式書寫、提高程式儲存效率、減少出錯率、增加程式的易讀性和可維護性,並且有利用子程式資源的組織和使用.設計子程式時,除了必需要考慮的程式調用、返回和完成特定功能的指令序列外,還必須注意解決子程式設計中帶有的共性的一些問題,即:現場保護、參數傳遞、子程式的嵌套與遞迴調用、編寫子程式說明文檔等.
1 現場保護
現場保護的目的是調用子程式之後,能夠返回主程式繼續執行.因此要對子程式中用到的寄存器,堆棧進行必要的保護.
1 1 寄存器保護因為組合語言程式中的主要操作對象是CPU中的各寄存器,對那些主程式和子程式中都會用到的一些寄存器要在子程式使用之前進行保護.寄存器保護最好是在子程式中進行,並且在子程式中進行恢複,這樣子程式顯得更完整.其方法是使用堆棧,由於指令系統中制定了規範的進棧指令PUSH和出棧指令POP,並會自動修改堆棧指標,只要在程式設計中注意8086/8088的堆棧是否按"後進先出"的原則組織的.
1 2 堆棧保護子程式是利用調用(CALL)指令和返回(RET)指令來實現正確的調用和返回的.因為CALL命令執行時壓入堆棧的斷點地址就是供子程式返回主程式時的地址,編程時一定要注意子程式的類型屬性,即是段內調用還是段間調用.段內調用和返回為NEAR屬性,段間調 王豔玲,等談談組合語言中子程式的設計方法37用和返回為FAR屬性.8086/8088的組譯工具用子程式定義PROC的類型屬性來確定CALL和RET指令的屬性.如果所定義的子程式是FAR屬性,那麼對它的調用和返回一定都是FAR屬性;如果所定義的子程式是NEAR屬性,那麼對它的調用和返回也一定是NEAR屬性.這樣使用者只是在定義子程式時考慮它的屬性,而CALL和RET指令的屬性就可以由組譯工具來確定了.另外,進入子程式後再使用堆棧時也必須保證壓入和彈出位元組數一致,如果在這裡堆棧存取出錯,必然會導致返回地址的錯誤.
2 參數傳遞
主程式在調用子程式時,經常要向子程式傳遞一些參數或控制資訊,子程式執行後,也常需要把啟動並執行結果返回調用程式.這種資訊傳遞稱為參數傳遞,其常用的方法有寄存器傳遞、記憶體固定單元傳遞、堆棧傳遞.
2 1 寄存器傳遞由主程式將要傳遞的參數裝入事先約定的寄存器中,轉入子程式後再取出進行處理,這種方法受CPU內部寄存器數量限制,因此只適於傳遞少量參數的場合,如一些常見的軟體延時子程式,均是利用某寄存器傳遞迴圈計數器初值.
2 2 通過記憶體固定單元的傳遞此方法適於大量傳遞參數時使用,它是在記憶體中開闢特定的一片地區用於傳遞參數.主程式和子程式都按事先約定在指定的儲存單元中進行資料交換,這種方法要佔用一定數量的儲存單元.不足之處是資訊易被修改,不利於模組化設計.
2 3 通過堆棧實現參數傳遞這種方法是先在主程式中把參數和參數地址壓入堆棧,在子程式中取出使用,由於堆棧操作不佔用寄存器,並且堆棧單元使用後可自動釋放,反覆使用,便於實現資料隔離和模組化設計.使用這種方法時,當子程式返回後,這些參數就不在有用了,應當丟棄.這時可以利用帶立即數的返回指令修改指標,使其指向參數入棧以前的值.
3 子程式嵌套與遞迴調用
組合語言中子程式的嵌套只要堆棧空間允許,一般不受嵌套層次限制.嵌套子程式設計中,應注意寄存器的保護與復原,避免各層子程式之間寄存器衝突.遞迴子程式的設計必須保證每次調用都不破壞以前調用時所用的參數和中間結果.為保證每次調用的正確,一般把每次調用的參數、有關寄存器的內容以及中間結果進棧儲存.
4 子程式說明文檔
一般來說子程式是要反覆使用或提供使用者使用,所以編寫子程式時應盡量採用較好的演算法,使子程式運行速度比較快,又節省記憶體.同時還應最大限度地滿足今後程式維護與使用的需要.在設計子程式的同時就應當建立相應的說明文檔,清楚地描述子程式的功能和調用方法.通常子程式說明文檔應包括:子程式名稱、子程式功能、入口參數、出口參數、工作寄存器、工作單元及最後修改日期等