Transcript Chapter 8

第 8 章:進階程序
章節概要
•
•
•
•
•
區域變數
堆疊參數
堆疊框
遞迴
建立多模組程式
Web site
Examples
2
區域指令
• 一個區域變數在一個程序裡面被產生使用,而且
破壞
• 區域指令宣布一連串的區域變數
• 立刻遵循 PROC 指令
• 每個變數被分配一個類型
• 語法:
LOCAL varlist
例題:
MySub PROC
LOCAL var1:BYTE, var2:WORD, var3:SDWORD
Web site
Examples
3
區域變數
例題:
LOCAL flagVals[20]:BYTE
; array of bytes
LOCAL pArray:PTR WORD
; pointer to an array
myProc PROC,
p1:PTR WORD
LOCAL t1:BYTE,
t2:WORD,
t3:DWORD,
t4:PTR DWORD
; procedure
; parameter
; local variables
Web site
Examples
4
MASM-生成代碼
(1 of 2)
BubbleSort PROC
LOCAL temp:DWORD, SwapFlag:BYTE
. . .
ret
BubbleSort ENDP
MASM產生下列的編碼:
BubbleSort PROC
push ebp
mov ebp,esp
add esp,0FFFFFFF8h
. . .
mov esp,ebp
pop ebp
ret
BubbleSort ENDP
; add -8 to ESP
Web site
Examples
5
MASM-生成代碼
(2 of 2)
堆疊的圖表為 BubbleSort 程序構成:
return address
EBP
ESP
EBP
temp
[EBP - 4]
SwapFlag
[EBP - 8]
Web site
Examples
6
堆疊參數
•
•
•
•
•
•
•
•
暫存器和堆疊參數比較
INVOKE 指引
PROC 指引
PROTO 指引
通過按價值計算比路過參考
參數分類
例子:交換二個整數
問題解析訣竅
Web site
Examples
7
暫存器和堆疊參數比較
• 暫存器參數需要把一個暫存器獻給每個參數。
• 想像呼叫 DumpMem 程序的二個可能方法。清楚地其
次比較容易:
pushad
mov esi,OFFSET array
mov ecx,LENGTHOF array
mov ebx,TYPE array
call DumpMem
popad
push
push
push
call
Web site
OFFSET array
LENGTHOF array
TYPE array
DumpMem
Examples
8
INVOKE 指引
• 那喚起指令是英代爾的呼叫指令的一個有力的替換讓
你通過多個爭論
• 語法:
INVOKE程序名稱 [引數清單 ]
• ArgumentList是一個傳遞給程序的可選用引數清單
• Arguments 能是:
•
•
•
•
立即的值和整數語法
變數名字
位址和 ADDR 語法
暫存器名字
Web site
Examples
9
INVOKE 例題
.data
byteVal BYTE 10
wordVal WORD 1000h
.code
; direct operands:
INVOKE Sub1,byteVal,wordVal
; address of variable:
INVOKE Sub2,ADDR byteVal
; register name, integer expression:
INVOKE Sub3,eax,(10 * 20)
; address expression (indirect operand):
INVOKE Sub4,[ebx]
Web site
Examples
10
ADDR運算子
• 會根據程式的記憶體模式所要求,來傳遞 near 指標或 far 指
標。
• 小的模型:回復16位元補償
• 大的模型:回復32位元分割/補償
• 平坦的模型: 回復32位元補償
• 簡單例題:
.data
myWord WORD ?
.code
INVOKE mySub,ADDR myWord
Web site
Examples
11
PROC 指引
• PROC 指令用一個命名的參數可選擇目錄宣布一個程
序.
• 語法:
label PROC paramList
• paramList 是被逗點分開的一連串的參數。每個參數有
下列的語法:
paramName:type
樣式必須或是標準ASM類型 (BYTE, SBYTE ,WORD,etc)之
一, 否則它可能是對這些類型之一的一個指標.
Web site
Examples
12
PROC 例題
(1 of 3)
• AddTwo 程序在 EAX 接受二個整數而且回復他們的總數.
• C++ 程式典型地在EAX回復來自功能的32位元整數。
AddTwo PROC,
val1:DWORD, val2:DWORD
mov eax,val1
add eax,val2
ret
AddTwo ENDP
Web site
Examples
13
PROC 例題
(2 of 3)
FillArray 接受對位元組的排列一個指標,一個位元組填滿將到排
列的每種元素 , 和排列的大小被複制的值。
FillArray PROC,
pArray:PTR BYTE, fillVal:BYTE
arraySize:DWORD
mov ecx,arraySize
mov esi,pArray
mov al,fillVal
L1: mov [esi],al
inc esi
loop L1
ret
FillArray ENDP
Web site
Examples
14
PROC 例題
(3 of 3)
Swap PROC,
pValX:PTR DWORD,
pValY:PTR DWORD
. . .
Swap ENDP
ReadFile PROC,
pBuffer:PTR BYTE
LOCAL fileHandle:DWORD
. . .
ReadFile ENDP
Web site
Examples
15
PROTO 指引
• 產生一個程序原型
• 語法:
• label PROTO paramList
• 每個程序順道拜訪那喚起指令一定要有一個原型
• 一種完全的程序定義也能視為ownprototype
Web site
Examples
16
PROTO 指引
• 標準結構: PROTO 在程式項目表的頂端出現,在編碼分割中
INVOKE出現,和程序履行稍後在程式中發生
MySub PROTO
; procedure prototype
.code
INVOKE MySub
; procedure call
MySub PROC
.
.
MySub ENDP
; procedure implementation
Web site
Examples
17
PROTO 例題
• 為 ArraySum 程序原型,顯示它的參數目錄:
ArraySum PROTO,
ptrArray:PTR DWORD,
szArray:DWORD
; points to the array
; array size
Web site
Examples
18
經過價值
• 當一個程序引數被經過價值的時候,複製16位元或32
位元整數是推動堆疊。
•
例題:
.data
myData WORD 1000h
.code
main PROC
INVOKE Sub1, myData
MASM 產生下列的編碼:
push myData
call Sub1
Web site
Examples
19
參考經過
• 當一個引數被經過參考的時候,它的位址是推動堆疊.
例題:
.data
myData WORD 1000h
.code
main PROC
INVOKE Sub1, ADDR myData
MASM 產生下列的編碼:
push OFFSET myData
call Sub1
Web site
Examples
20
參數分類
• 輸入: 輸入參數即為,由呼叫者程式傳遞給被呼叫程序的資料。
我們不期望被呼叫程序修改 到對應的參數變數,即使它這麼做了,
修改的效果也應該只侷限在程序本身以內。
• 輸出: 當呼叫者程式傳遞某個變數的位址給一個程序時,就會建立起
輸出參數。 程序可以使 用這個位址找到該變數,並且指定資料給該變
數。
• 輸入 - 輸出: 輸入 - 輸出參數與輸出參數幾乎完全相同,它們的差異
點是: 被呼叫的程序會預 期,由參數所參照的變數將含有一些資料。
Web site
Examples
21
範例: 交換兩個整數
使用到的 Swap 程序具有兩個 輸入 - 輸出參數,其名稱分別為
pValX 和 pValY,這兩個參數所含有的,就是要進行交換 的資料
的位址:
Swap PROC USES eax esi edi,
pValX:PTR DWORD,
; pointer to first integer
pValY:PTR DWORD
; pointer to second integer
mov esi,pValX
mov edi,pValY
mov eax,[esi]
xchg eax,[edi]
mov [esi],eax
ret
Swap ENDP
; get pointers
; get first integer
; exchange with second
; replace first integer
Web site
Examples
22
除錯的訣竅
• 當他們被一個程序修正的時候,儲存而且回復暫存器.
• 除了一個暫存器回復產生一個函數
• 當使用INVOKE的時候,小心通過一個指標給正確的資料類型.
• 舉例來說, MASM 不能夠區別一個 DWORD 引數和一個
PTR 位元組引數。
• 不要傳遞給它立即值引數.
• 遵從它的位址將或許引起一種普通保護的過失。
Web site
Examples
23
堆疊框
•
•
•
•
•
記憶體模式
語言 Specifiers
明確准入堆疊參數
經過引數的參考
創造區域變數
Web site
Examples
24
堆疊框
• 知道當做一筆啟動記錄
• 堆疊的區域對於一個程序的回復位址留存,經過參數,
保存了暫存器,和區域變數
• 藉著下列步驟產生:
• 呼叫子常式,因而導致子常式的返回位址被壓進堆疊中.
• EBP 設定等於 ESP。 從這個時候開始,EBP 的作用是
當作所有子常式參數的基底參考。.
• 如有任何區域變數存在,則我們可將 ESP 減去某值,
以便在堆疊中保留區域變數的儲存空間。
Web site
Examples
25
記憶體模式
• 一個程式的記憶體模式決定數字和編碼和資料分割的
大小.
• 實體位址模式下的程式tiny, small, medium, compact,
large, 和 huge 模式.
• 在保護模式下的程式,使用的是 flat 記憶體.
Small model: code < 64 KB, data (including stack) < 64 KB.
All offsets are 16 bits.
Flat model: single segment for code and data, up to 4 GB.
All offsets are 32 bits.
Web site
Examples
26
.MODEL 指令
• 模式的指定符一個程式的記憶體模式和模式的選擇。
(語言-指定符)
• 語法:
.MODEL memorymodel [,modeloptions]
• 記憶體模式可能是下列各項之一:
• tiny, small, medium, compact, large, huge, 或 flat
• 模是選項包括語言指定符:
• 程序取名方案
• 參數經過慣例
Web site
Examples
27
語言指定符
• C:
• 指定符會要求程序引數,以相反順序壓進堆疊(向右離開)
• 呼叫程式清除堆疊
• pascal
• 程序引數順向壓進(由左至右)
• 呼叫程式清除堆疊
• stdcall
• 指定符會要求程序引數,以相反順序壓進堆疊(由右至左)
• 呼叫程式清除堆疊
Web site
Examples
28
明確經過堆積參數
• 一個程序能明確取得使用來自 EBP1 的常數彌補的堆
疊參數.
• 例題: [ebp + 8]
• 因為它支撐堆疊結構的基礎位址,所以 EBP 時常被稱
為基礎的指標或者結構指標.
• EBP 不在程序的時候改變值.
• 當一個程序回復時,EBP一定要對它的最初值回復.
Web site
Examples
29
堆疊框例子(1 of 2)
.data
sum DWORD ?
.code
push 6
push 5
call AddTwo
mov sum,eax
AddTwo PROC
push ebp
mov ebp,esp
.
.
;
;
;
;
second argument
first argument
EAX = sum
save the sum
00000006
[EBP + 12]
00000005
[EBP + 8]
return address
[EBP + 4]
EBP
Web site
EBP, ESP
Examples
30
堆疊框例題
00000006
[EBP + 12]
00000005
[EBP + 8]
return address
[EBP + 4]
EBP
(2 of 2)
EBP, ESP
AddTwo PROC
push ebp
mov ebp,esp
mov eax,[ebp + 12]
add eax,[ebp + 8]
pop ebp
ret 8
AddTwo ENDP
; base of stack frame
; second argument (6)
; first argument (5)
; clean up the stack
; EAX contains the sum
Web site
Examples
31
習題. . .
• 產生一個叫做減去來自第二個的第一個引數不同的程
序。下列各項是一個樣本呼叫:
push 14
push 30
call Difference
Difference PROC
push ebp
mov ebp,esp
mov eax,[ebp + 8]
sub eax,[ebp + 12]
pop ebp
ret 8
Difference ENDP
; first argument
; second argument
; EAX = 16
; second argument
; first argument
Web site
Examples
32
參考經過引數(1 of 2)
• ArrayFill 程序,可使一個陣列填入由 16 位元整數所
組成的擬隨機數列。
• 第一 個引數利用參考的方式加以傳遞,第二個則使用
傳值的方式傳遞。 以下是一個示範呼叫:
.data
count = 100
array WORD count DUP(?)
.code
push OFFSET array
push COUNT
call ArrayFill
Web site
Examples
33
參考經過引數(2 of 2)
ArrayFill 能參考排列不知道排列的命名:
ArrayFill PROC
push ebp
mov ebp,esp
pushad
mov esi,[ebp+12]
mov ecx,[ebp+8]
.
.
offset(array)
[EBP + 12]
count
[EBP + 8]
return address
EBP
EBP
ESI 指向排列的開始,因此,使用一個迴路取得每種排列元素是
容易的.顯示完全的計畫.
Web site
Examples
34
LEA指令
• LEA 指令用於回傳間接運算元的位移.
• 彌補運算能唯一的回復常數彌補.
• 當獲得堆疊參數或區域變數的彌補時, 需要LEA .舉
例來說:
CopyString PROC,
count:DWORD
LOCAL temp[20]:BYTE
mov
mov
lea
lea
edi,OFFSET count
esi,OFFSET temp
edi,count
esi,temp
;
;
;
;
Web site
invalid operand
invalid operand
ok
ok
Examples
35
產生區域變數
• 為了要明確地產生區域變數,減去來自 ESP 總數大小.
• 下列的例子產生並且設定二個 32 位元區域變數初值:
(我們稱它們為locA和locB)
MySub PROC
push ebp
mov ebp,esp
sub esp,8
mov [ebp-4],123456h
mov [ebp-8],0
.
.
Web site
; locA
; locB
Examples
36
遞迴
• 遞迴是甚麼?
• 遞迴計算總數
• 計算階乘
Web site
Examples
37
遞迴是甚麼?
• 程序產生當. . .
• 一個程序呼叫本身
• 程序A呼叫程序B,依次呼叫程序A
• 使用一個圖表在每個節是程序和每個邊緣是一個程序
呼叫,遞迴形成一個周期:
A
E
B
D
C
Web site
Examples
38
遞迴計算總數
CalcSum 程序遞迴計算整數排列的總數: ECX = count. Returns:
EAX = sum
CalcSum PROC
cmp ecx,0
jz L2
add eax,ecx
dec ecx
call CalcSum
L2: ret
CalcSum ENDP
;
;
;
;
;
check counter value
quit if zero
otherwise, add to sum
decrement counter
recursive call
顯示完全計畫
Stack frame:
Web site
Examples
39
計算階乘(1 of 3)
這一個功能計算整數 n 的階乘。n 的新數值在每個堆疊框中被
保存:
int function factorial(int n)
{
if(n == 0)
return 1;
else
return n * factorial(n-1);
}
As each call instance returns, the
product it returns is multiplied by the
previous value of n.
recursive calls
backing up
5! = 5 * 4!
5 * 24 = 120
4! = 4 * 3!
4 * 6 = 24
3! = 3 * 2!
3*2=6
2! = 2 * 1!
2*1=2
1! = 1 * 0!
1*1=1
0! = 1
1=1
(base case)
Web site
Examples
40
計算階乘(2 of 3)
Factorial PROC
push ebp
mov ebp,esp
mov eax,[ebp+8]
cmp eax,0
ja
L1
mov eax,1
jmp L2
;
;
;
;
L1: dec eax
push eax
call Factorial
get n
n < 0?
yes: continue
no: return 1
; Factorial(n-1)
; Instructions from this point on execute when each
; recursive call returns.
ReturnFact:
mov ebx,[ebp+8]
mul ebx
; get n
; ax = ax * bx
L2: pop ebp
ret 4
Factorial ENDP
; return EAX
; clean up stack
看計畫項目表
Web site
Examples
41
計算階乘(3 of 3)
12
n
ReturnMain
ebp0
假如我們想要計算 12!
11
這一個圖表顯示第一個少
數堆疊框架
ReturnFact
藉著對階乘的遞迴呼叫產
生
10
每個遞迴的呼叫使用 12個
位元組的堆疊空間.
n-1
ebp1
n-2
ReturnFact
ebp2
9
n-3
ReturnFact
ebp3
(etc...)
Web site
Examples
42
多模組程式
• 一個多模組程式是一個原始碼已經進入隔開ASM檔案
之內被均分的程式.
• 每個ASM檔案 (模組)進入一個隔開的 OBJ 檔案之
內被裝配。
• 屬於相同的程式所有的 OBJ 檔案被連接使用連結實效
進入一個 EXE 檔案.
• 這一個程序叫做靜態連接
Web site
Examples
43
優點
• 當區分為隔開的原始碼組件,大的程式比較容易寫,
保持,而且除錯.
• 當改變一列編碼的時候,它關閉模組需要在再一次被組合。
• 一個模組可能是合乎邏輯相關的編碼和資料的一個容
器(物體-在這裡導向…)。
• 封裝 :將模組內的程 序隱藏起來
Web site
Examples
44
產生一個多模組程式
• 當產生一個多模組計畫的時候,這裡是遵從的一
些基本步驟:
• 產生主要的模組
• 為每個程序或相關程序的模組產生一個隔開的原始
碼組件
• 產生一包括為外部的程序包含程序原型的檔案(在
模組之間被叫做)
• 使用那INCLUDE指令使你的程序設計原型可得的
到每個模組
Web site
Examples
45
範例: ArraySum程式
• ArraySum 程式是在第 5 章出現
Summation
Program (main)
Clrscr
PromptForIntegers
WriteString
ArraySum
ReadInt
DisplaySum
WriteString
WriteInt
四個白色的長方形將變成每一個模組.
Web site
Examples
46
例子程式輸出
Enter a signed integer: -25
Enter a signed integer: 36
Enter a signed integer: 42
The sum of the integers is: +53
Web site
Examples
47
INCLUDE 檔案
sum.inc 檔案包含原型外部的功能沒有在Irvine 32 資料庫中:
INCLUDE Irvine32.inc
PromptForIntegers PROTO,
ptrPrompt:PTR BYTE,
ptrArray:PTR DWORD,
arraySize:DWORD
; prompt string
; points to the array
; size of the array
ArraySum PROTO,
ptrArray:PTR DWORD,
count:DWORD
; points to the array
; size of the array
DisplaySum PROTO,
ptrPrompt:PTR BYTE,
theSum:DWORD
; prompt string
; sum of the array
Web site
Examples
48
檢查個別的模組
•
•
•
•
Main
PromptForIntegers
ArraySum
DisplaySum
訂製一組檔案來集合與連接.
Web site
Examples
49
The End
Web site
Examples
50