一個簡單的包含子程式的彙程式設計式是:
編譯、連接配接後,用debug觀察到:
從<code>call</code>對應的機器指令中,可以看到這是一種近(near)調用,機器指令<code>eb0500</code>中可以取出要調用的子程式,其偏移位址的位移是<code>0005</code>。
進一步,用t指令,可以觀察在調用子程式時,棧的變化過程,進而深刻了解子程式的機理。
編譯、連接配接,用debug載入後,我們觀察:
這就是遠調用!在機器指令中,直接指定了子程式的cs和ip。
繼續單步執行,觀察在調用過程中棧的變化。這個觀察,對我們了解程式設計中的子程式機制非常重要。
下面,要将程式變個樣。話從何說起呢?我懷念c語言中的<code>{}</code>了。将一段邏輯上相關的代碼,放在<code>{}</code>中,看起來就有邊有沿的,整齊,帶來的好處,可讀性提高,更關鍵的好處,程式的可讀性提高。
于是有了下面的寫法。
從中看到,一個程式,分為若幹個子程式,每個子程式長下面的樣子:
最為關鍵的就是,将一段程式,我們認為是邏輯功能獨立的子程式,用兩個關鍵字,<code>proc</code>和<code>endp</code>,包圍成了一個整體。
子程式的名稱,其實質也是代碼的位址。如果子程式就是從第一條指令開始,按下面的寫法也行:
冥冥中,我看到我c中的:
子產品化的味道出來了吧?
我們更進一步!
有人說,彙編隻能編小程式。
我替我彙說:不服!
當編大程式時,分子產品做就行了。更關鍵的,從工程組織的角度,進階語言能夠将代碼分别寫在多個檔案中,彙編語言照樣能這麼幹!
怕有人郁悶,我悄悄地告訴大家,這一招,進階語言是從彙編語言處學的。其實,程式設計技術都是相通的,大家不要搞得不像一家人。
把上面的程式,分在兩個檔案中,一個檔案中一個子程式:
step 1:建立“主程式”檔案
将p1.asm單獨編譯:
強烈建議:将<code>extrn subp:far</code>省略掉,看看會出現什麼?
step 2:建立“子程式”檔案
編譯p2.asm:
step 3:連接配接
上述的兩個.asm經過編譯後,産生了兩個.obj檔案,分别是p1.obj和p2.obj。現在要做的工作,就是把這兩個目标檔案連接配接成一個可執行檔案。
用的指令是:
連接配接的結果,産生了可執行檔案p1.exe。
同學們,知道“連接配接”是什麼意思了吧?再來多個檔案,繼續”+”好了。大工程,真的不懼。
提示:将step 2中的<code>public subp</code>去掉,看看連接配接中會出現什麼問題。進一步思考,在連接配接中有什麼要求
step 4:運作程式
駕輕就熟的事情,debug就行。
“子程式”的代碼哪去了?
可以發現,現在隻是“主程式”的代碼,主程式在076b段,而子程式,從子程式調用的指令看,在076d段。
繼續看:
呵呵,這就找到了。
本文用一個很簡單的例子,介紹了彙編語言引入子程式後,程式的結構,以及多檔案組織的形式。程式簡單了些,但道理都在裡面呢。
可以做一個練習,主程式調用子程式玩一玩。
【練習】
(1)版本1:子程式的參數由寄存器dl提供,傳回結果在ax中;
(2)版本2:子程式不變,主程式中提供如下資料區,在主程式中,循環調用子程式,完成y=x4的求解,并将結果存入在相應的資料區:
(3)版本3:資料區不變,子程式完成全部8個資料的求解任務,主程式隻調用一次子程式即可。資料x的起始偏移位址由si提供,存放結果的y的偏移位址,由di提供,在調用前,由主程式為子程式提供si、di值。
(4)版本4:将上面的程式按多檔案的方式存放。