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