第 5 章:程序
本章概述 連結外部函式庫 運用程序的程式設計 堆疊運算 定義和使用程序
本書所用的連結函式庫 連結函市庫概觀 呼叫一個函市庫程序 到一個函市庫連結 函市庫程序-概觀 六個例子
連結函市庫概觀 一個包含已經進入機器之內被編譯的程序的檔案 建立一間函式庫 . . . 從一個或更多的 OBJ 檔案構造 從一或更多的ASM來源檔案開始 組合每個進入一個 OBJ 檔案 創造一個空的函市庫檔案(延長 LIB) 把 OBJ 檔案 (s)加入函市庫檔案,使用微軟 LIB 實效 藉由在這一個螢幕的底部按下例子快看 Irvine32. asm.
呼叫一個函市庫程序 呼叫使用指令的一個函市庫程序.一些程序需要輸入引數.那在程序原型中包括指令的副本(公告). 下列的例子在控制檯上顯示 "1234" : INCLUDE Irvine32.inc .code mov eax,1234h ; input argument call WriteHex ; show hex number call Crlf ; end of line
到一個函市庫連接 後者是微軟贏 32 軟體發展配套的部份(SDK) 對使用一個被命名的檔案裡連接器指令 Irvine32. lib 你的程式連結make32.bat. 注意二個 LIB 檔案:Irvine32. lib, 和kerne 32.lib 後者是微軟贏 32 軟體發展配套的部份(SDK)
下一章 連結外部函式庫 本書所用的連結函式庫 堆疊運算 定義而且使用程序 運用程序的程式設計
函式庫程序-概觀(1 of 4) EFLAGS 及EIP 等暫存器的內容值。同時也顯示最常用到的CPU 狀態旗標 CloseFile -將先前開啟的磁碟檔案予以關閉 Clrscr -清除主控台視窗,並將游標重新定位於左上角 CreateOutputFile -建立一個能在輸出模式下寫入資料的新磁碟檔案 Crlf -寫入一個行末 (end-of-line) 標記到主控台視窗 Delay -將程式的執行暫停n個毫秒的時間間隔 DumpMem -以十六進位的表示方式,將一個區塊的記憶體內容寫入到主控台視窗 DumpRegs –以十六進位的方式顯示EAX、EBX、ECX、EDX、ESI、EDI、EBP、ESP、 EFLAGS 及EIP 等暫存器的內容值。同時也顯示最常用到的CPU 狀態旗標 GetCommandtail -複製程式命令列的參數 ( 也稱為command tail) 到一個由位元組所組成的陣列裡 GetMaxXY -取得主控台視窗的緩衝區的行數與列數 GetMseconds -回傳一個從午夜十二點之後所經過的時間值,以毫秒為單位
函式庫程序-概觀(2 of 4) GetTextColor -回傳現行的主控台視窗的文字顏色和底色 Gotoxy -在主控台視窗中,將游標定位到指定的行與列的位置上 IsDigit -如果AL 暫存器所含有的ASCII 碼是十進位數字(0-9),則設定零值旗標 MsgBox, MsgBoxAsk –顯示一個彈出式訊息視窗,在彈出式視窗中顯示是/ 否的問題 OpenInputFile –開啟一個現存的磁碟檔案用於輸入 ParseDecimal32 –將一個無號的十進位整數字串轉換成32 位元二進位整數 ParseInteger32 -將一個有號的十進位整數字串轉換成32 位元二進位整數 Random32 -產生一個32 位元的擬隨機整數,其數值範圍在0到FFFFFFFF 之間 Randomize -以一個唯一值,作為隨機數產生器的種數 RandomRange -產生一個位於某個指定範圍內的擬隨機整數 ReadChar -等待一個由鍵盤所輸入的單一字元,並且回傳該字元
函式庫程序-概觀(3 of 4) ReadFromFile –由輸入的磁碟檔案讀取資料到緩衝區中 ReadDec -由鍵盤讀取一個無號的32 位元十進位整數,並且在接收到Enter 鍵時結束讀取動作 ReadHex -由鍵盤讀取一個32 位元的十六進位整數,並在接收到[Enter] 鍵時結束讀取動作 ReadInt -由鍵盤讀取一個32 位元的有號十進位整數,並且在接收到[Enter ] 鍵時結束讀取動作 ReadKey –在不等待輸入動作的情形下,由鍵盤的輸入緩衝區讀取一個字元 ReadString -由鍵盤讀取一個字串,並且在接收到Enter 鍵時結束讀取的動作 SetTextColor -設定隨後要輸出到主控台的文字的顏色和底色 StrLength –回傳字串的長度 WaitMsg -顯示一個訊息,並且等待一個鍵被按下 WriteBin -以ASCII 二進位格式,寫入一個無號的32 位元整數到主控台視窗 WriteBinB –以位元組、字組或雙字組的格式,將一個二進位整數寫到主控台視窗 WriteChar -將單一個字元寫入到主控台視窗
函式庫程序-概觀(4 of 4) WriteDec -以十進位格式寫入一個無號的32 位元整數到主控台視窗 WriteHex -以十六進位格式寫入一個無號的32 位元整數到主控台視窗 WriteHexB –以十六進位格式,將一個位元組、字組或雙字組整數寫到主控台視窗 WriteInt -以十進位格式寫入一個有號的32 位元整數到主控台視窗 WriteString -將一個以空字元作為結尾的字串寫到主控台視窗 WriteToFile -將一個緩衝區寫到輸出檔案 WriteWindowsMsg -將含有由MS-Windows 所產生最近一個訊息的字串顯示出來
例子1 清除螢幕,為 500 毫秒延遲計畫,而且傾卸暫存器和旗標. 樣本輸出: .code call Clrscr mov eax,500 call Delay call DumpRegs EAX=00000613 EBX=00000000 ECX=000000FF EDX=00000000 ESI=00000000 EDI=00000100 EBP=0000091E ESP=000000F6 EIP=00401026 EFL=00000286 CF=0 SF=1 ZF=0 OF=0 樣本輸出:
例子 2 顯示零-結束了列而且移動游標到下一個螢幕線的開始. .data str1 BYTE "Assembly language is easy!",0 .code mov edx,OFFSET str1 call WriteString call Crlf
例子 2a 顯示零-結束了字串而且移動游標到下一個螢幕線的開始(使用植入的 CR/LF) .data str1 BYTE "Assembly language is easy!",0Dh,0Ah,0 .code mov edx,OFFSET str1 call WriteString
例子 3 顯示在二進位,十進位和十六進位的一個未被簽署的整數,每個在一條單獨的列上 Sample output : IntVal = 35 .code mov eax,IntVal call WriteBin ; display binary call Crlf call WriteDec ; display decimal call WriteHex ; display hexadecimal 0000 0000 0000 0000 0000 0000 0010 0011 35 23 Sample output :
Example 4 輸入來自使用者的字串。 EDX 指向線和 ECX 記載使用者被允許進入的最大字元的數字。 .data fileName BYTE 80 DUP(0) .code mov edx,OFFSET fileName mov ecx,SIZEOF fileName – 1 call ReadString 一個無效力的位元組自動地到字串被附加.
例子 5 產生並且顯示十個假散亂在範圍 0-99 中標示整數.在一條單獨的列上通過每個整數給在 EAX 中的 WriteInt 而且顯示它。 .code mov ecx,10 ; loop counter L1: mov eax,100 ; ceiling value call RandomRange ; generate random int call WriteInt ; display signed int call Crlf ; goto next display line loop L1 ; repeat loop
例子 6 顯示零-和在藍色的背景上的黃色的個性結束了字串. 背景顏色在 16 點之前在被加到前景顏色之前被繁殖。 .data str1 BYTE "Color output is easy!",0 .code mov eax,yellow + (blue * 16) call SetTextColor mov edx,OFFSET str1 call WriteString call Crlf 背景顏色在 16 點之前在被加到前景顏色之前被繁殖。
下一章 連結外部函式庫 本書所用的連結函式庫 堆疊運算 定義和使用程序 運用程序的程式設計
堆疊運算 執行時期堆疊 PUSH 運算 POP 運算 PUSH 和 POP指令 使用 PUSH 和 POP 例子:字串倒轉 相關的指令
執行時期堆疊 想像板塊的堆疊. . . 板塊只被加到頂端 板塊只從頂端被移動 LIFO結構
執行時期堆疊 藉著中央處理器處理,使用二個暫存器 SS (堆疊片段) ESP (堆疊指針) * * SP in Real-address mode
PUSH 運算(1 of 2) 一個 32位元推動行動漸減堆疊指針在 4 之前而且拷貝價值進入被堆疊指針指向的地點。
PUSH 運算 (2 of 2) 相同的堆疊在推動另外二個整數之後: 在 ESP 下面的區域總是可得的。(除非堆疊已經氾濫)
POP 運算 副本進入一個暫存器或變數之內在堆疊〔ESP〕評價. 把 n 加入 ESP, n 是或 2 或 4.
PUSH 和 POP 指令 PUSH 語法: POP 語法: PUSH r/m16 PUSH r/m32 PUSH imm32 POP r/m16 POP r/m32
使用 PUSH 和 POP 當他們包含重要的價值時候,解救而且回復暫存器.PUSH和POP協議指導在相反的次序中發生 . push esi ; push registers push ecx push ebx mov esi,OFFSET dwordVal ; display some memory mov ecx,LENGTHOF dwordVal mov ebx,TYPE dwordVal call DumpMem pop ebx ; restore registers pop ecx pop esi
例子:築巢環路 當創造一個被巢狀環路的時候,在進入內部的環路之前推動外部的環路櫃台: mov ecx,100 ; set outer loop count L1: ; begin the outer loop push ecx ; save outer loop count mov ecx,20 ; set inner loop count L2: ; begin the inner loop ; loop L2 ; repeat the inner loop pop ecx ; restore outer loop count loop L1 ; repeat the outer loop
例子:字串倒轉 因為只有字 (16 位元)或 doubleword(32 位元)價值能是急忙前進壓入。 和編入索引一起使用一個環演說 push在堆疊上的每個字符 從最初的地方開始字串,彈出在反面的次序中的堆疊,進入字串之內把每個字符插入回來 原始碼 Q: 壓入之前,為什麼每個字符必須被提出 EAX? 因為只有字 (16 位元)或 doubleword(32 位元)價值能是急忙前進壓入。
你輪到的. . . 以相反規劃的字串作為出發點, #1:修正計畫,如此使用者能輸入在 1 和 50個字符之間包含的字串. #2:修正計畫,如此它輸入來自使用者的一連串的 32 位元整數,然後在反面的次序中顯示整數.
相關的指令 PUSHFD 和 POPFD PUSHAD 推動在堆疊上的 32 位元泛用型的暫存器 push 和 pop the EFLAGS 暫存器 PUSHAD 推動在堆疊上的 32 位元泛用型的暫存器 命令: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI POPAD 在反面的次序中從堆疊彈出相同的暫存器 PUSHA 和 POPA 為 16 位元暫存器做一樣的
你輪到的. . . 寫一個跟隨的計畫: 分配整數價值到 EAX , EBX , ECX , EDX , ESI 和 EDI 使用 PUSHAD 推動在堆疊上的泛用型的暫存器 使用一個環路,你的計畫應該彈出來自堆疊的每個整數而且在螢幕上顯示它
下一章 連結外部函式庫 本書所用的連結函式庫 堆疊運算 定義和使用程序 運用程序的程式設計
定義和使用程序 創造程序 程序的註解說明 例子: SumOf 程序 CALL 和 RET 指令 巢狀程序呼叫 Local 和 Global 標籤 程序參數 流程表象徵 USES 運算
創造程序 大的問題能被區分為更小的工作使他們變成更易辦 一個程序是美國金屬學會同等Java 或 C++函數 下列各項是一個被命名的組合語言程序 例子: sample PROC . ret sample ENDP
程序的註解說明 為每個程序建議了文件: 如果一個程序沒有被滿意它的先決條件被叫,它可能將不生產預期的輸出. 所有工作的描述完成的藉著程序. 接受:一連串的輸入參數;陳述他們的用法和需求。 回返:被程序歸還的價值的描述. 需要:在程序被叫做之前,需求的可選擇目錄呼叫了一定要被滿意的先決條件。 如果一個程序沒有被滿意它的先決條件被叫,它可能將不生產預期的輸出.
例子:程序的總數 ;--------------------------------------------------------- SumOf PROC ; ; Calculates and returns the sum of three 32-bit integers. ; Receives: EAX, EBX, ECX, the three integers. May be ; signed or unsigned. ; Returns: EAX = sum, and the status flags (Carry, ; Overflow, etc.) are changed. ; Requires: nothing add eax,ebx add eax,ecx ret SumOf ENDP
CALL 和 RET 指令 呼叫指令呼叫一個程序 關於壓入抵銷的下個操作的堆疊 RET來自一個程序的指令回返 複印被叫做的程序位址進入 EIP RET來自一個程序的指令回返 彈出堆疊的頂端進入EIP
CALL-RET 例子(1 of 2) main PROC 00000020 call MySub 00000025 mov eax,ebx . main ENDP MySub PROC 00000040 mov eax,edx ret MySub ENDP 0000025 是指令的抵銷立刻跟隨呼叫指令 00000040 在 MySub 內是第一個指令的抵銷
CALL-RET 例子 (2 of 2) (以前堆積顯示RET執行) 呼叫指令在堆疊之上壓入 00000025,而且進入 EIP 之內裝載 00000040 那RET指令彈出 00000025 從堆疊到 EIP (以前堆積顯示RET執行)
巢狀了程序呼叫 在時間之前 Sub3 被叫做,堆疊包含所有的三個回返位址:
Local 和Global 標籤 當地標籤只在相同的程序內到陳述是看得見的.全球的標籤各處是看得見的. main PROC jmp L2 ; error L1:: ; global label exit main ENDP sub2 PROC L2: ; local label jmp L1 ; ok ret sub2 ENDP
程序參數(1 of 3) 一個好程序可能在許多不同的計畫中是可使用的 因為參數價值能在運行時間改變,所以參數幫助使程序有彈性 但如果沒提特定的可變名字 因為參數價值能在運行時間改變,所以參數幫助使程序有彈性
程序參數(2 of 3) ArraySum 程序計算排列的總數。它作二個關於特定的可變名字的參考: ArraySum PROC mov esi,0 ; array index mov eax,0 ; set the sum to zero mov ecx,LENGTHOF myarray ; set number of elements L1: add eax,myArray[esi] ; add each integer to sum add esi,4 ; point to next integer loop L1 ; repeat for array size mov theSum,eax ; store the sum ret ArraySum ENDP 如果你想要在相同的計畫裡面計算二或三排列的總數?
程序參數(3 of 3) ArraySum 的這一個版本復原位址在 ESI 的任何 doubleword 排列的總數。總數在 EAX 被復原: ArraySum PROC ; Receives: ESI points to an array of doublewords, ; ECX = number of array elements. ; Returns: EAX = sum ;----------------------------------------------------- mov eax,0 ; set the sum to zero L1: add eax,[esi] ; add each integer to sum add esi,4 ; point to next integer loop L1 ; repeat for array size ret ArraySum ENDP
流程表符號 下列的符號是流程表的基本方塊: (包括在書的第 166 頁上不被列出的二個符號.)
為 ArraySum 程序的流程表
你輪到的. . . 畫一個表達下列的pseudocode的流程表 input exam grade from the user if( grade > 70 ) display "Pass" else display "Fail" endif
. . . (解答)
你輪到的. . . 在先前的幻燈片中修正流程表讓使用者繼續輸入考試得分直到 -1 的價值被進入
USES 運算 列出將被保持的暫存器 MASM generates the code shown in gold: ArraySum PROC USES esi ecx mov eax,0 ; set the sum to zero etc. MASM generates the code shown in gold: ArraySum PROC push esi push ecx . pop ecx pop esi ret ArraySum ENDP
當不要再推動一個暫存器 三個暫存器的總數被儲存在列 (3) 上的 EAX, 但是pop協議指導以 EAX 對列的出發價值替換它: (4) SumOf PROC ; sum of three integers push eax ; 1 add eax,ebx ; 2 add eax,ecx ; 3 pop eax ; 4 ret SumOf ENDP
下一章 連結外部函式庫 本書所用的連結函式庫 堆疊運算 定義和使用程序 運用程序的程式設計
規劃使用程序的設計 由上而下的設計 (功能的分解)包括下列各項: 在開始編碼之前設計你的計畫 中斷大的工作進入更小的一些 使用以程序呼叫為基礎的階層的結構 分開地測試個別的程序
整數總和計畫(1 of 4) 描述:寫一個對於多個 32 位元整數促使使用者的計畫,在排列中儲存他們,計算排列的總數,而且顯示在螢幕上的總數。 主要部份步驟: 為多個整數的提示使用者 計算排列的總數 顯示總數
程序設計(2 of 4) Main Clrscr ; 清除螢幕 PromptForIntegers WriteString ; 顯示字串 ReadInt ; 數入整數 ArraySum ; 整數總加 DisplaySum WriteInt ; 顯示整數
結構圖(3 of 4) 灰色指出程式館程序 顯示 stub program 顯示final program
樣本輸出(4 of 4) Enter a signed integer: 550 Enter a signed integer: -23 The sum of the integers is: +431
摘要 程序–命名了可執行編碼的區段 執行時期堆疊– LIFO 構成 使用irvine32 程式館作為所有的標準輸入/輸出和資料轉變 保存回復位址,參數,局部變數 PUSH –增加數值堆疊 POP –除去堆疊的距離數值 使用irvine32 程式館作為所有的標準輸入/輸出和資料轉變 在 c:\ Irvine\examples\Lib32 文件夾中學習程式館原始碼
結束