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