770 likes | 1.06k Views
單元 4: 資料轉移、定址和算術. 章節概念. 資料轉移指令 加法與減法 資料相關的運算子和指引 間接定址 JMP 和 LOOP 指令. 直接位移指令. 運算元型別 命令運算元表示法 直接記憶運算元 MOV 指令 整數的補零 / 符號擴展 XCHG 指令 直接位移指令. 運算元型別. 三種類型的指令運算 立即 – 一個連續整數 (8, 16, or 32 bits) value is encoded within the instruction 暫存器 – the name of a register
E N D
章節概念 • 資料轉移指令 • 加法與減法 • 資料相關的運算子和指引 • 間接定址 • JMP和LOOP指令
直接位移指令 • 運算元型別 • 命令運算元表示法 • 直接記憶運算元 • MOV 指令 • 整數的補零/符號擴展 • XCHG 指令 • 直接位移指令
運算元型別 • 三種類型的指令運算 • 立即 – 一個連續整數 (8, 16, or 32 bits) • value is encoded within the instruction • 暫存器 – the name of a register • register name is converted to a number and encoded within the instruction • 記憶體 – reference to a location in memory • memory address is encoded within the instruction, or a register holds the address of a memory location
直接記憶體運算元 • 變數名稱參照 (reference) 的是資料區段中的位移值。 • 程式碼會含有能使用記憶體運算元的位址,來解參照 (dereference) 該運算元的指令。 .data var1 BYTE 10h .code mov al,var1 ; AL = 10h mov al,[var1] ; AL = 10h alternate format
MOV 指令 • 指令會將資料從來源運算元複製到目的運算元。 • 語法: MOV 目的地 , 來源 • 兩個運算元必須具有相同的大小。 • CS、EIP 及 IP 不可以當作目的運算元。 • 兩個運算元不能都是記憶體運算元。 • 一個立即值不能搬移至區段暫存器。 .data count BYTE 100 wVal WORD 2 .code mov bl,count mov ax,wVal mov count,al mov al,wVal ; error mov ax,count ; error mov eax,count ; error
換你 . . . 解釋為什麼下列的MOV指令都是有錯誤的?? : .data bVal BYTE 100 bVal2 BYTE ? wVal WORD 2 dVal DWORD 5 .code mov ds,45 mov esi,wVal mov eip,dVal mov 25,bVal mov bVal2,bVal 不被允許直接向DS移動 大小不同 EIP 不能當目的地的 立即的數值是不能當目的地的 兩個運算元都是記憶體是不被允許的
整數的補零 當你複製小的運算元到大的運算元時, 這個MOVZX指令會將它的剩餘各位元填上零值。 mov bl,10001111b movzx ax,bl ; 整數的補零 目的地一定是一個暫存器.
符號擴展 ,它會複製 來源運算元的內容到目的運算元,並且不論目的運算元是 16 位元或 32 位元,都會將它 的剩餘各位元填上符號位元。 mov bl,10001111b movsx ax,bl ; 符號的擴展 目的地一定要是暫存器.
XCHG 指令 XCHG將兩個運算元的內容互相 交換. 其中一個運算元一定是一個暫存器. 沒有立即的運算元是被充許的. .data var1 WORD 1000h var2 WORD 2000h .code xchg ax,bx ;將兩個16位元暫存器的內容互相交換 xchg ah,al ;將兩個0位元暫存器的內容互相交換 xchg var1,bx ;將16位元的記憶體運算元與 BX 互相交換 xchg eax,ebx ;將兩個32位元暫存器的內容互相交換 xchg var1,var2 ; 錯誤: 兩個都是記憶運算元
直接位移運算元 我們可將某個移位值加到一個變數名稱上,因而建立直接位移運算元。 這讓程式設計員 可以針對沒有明確標籤的記憶體位址進行存取的動作。 .data arrayB BYTE 10h,20h,30h,40h .code mov al,arrayB+1 ; AL = 20h mov al,[arrayB+1] ; alternative notation Q:為何 arrayB+1不產生 11h?
直接位移運算元(內容) 我們可將某個移位值加到一個變數名稱上,因而建立直接位移運算元。 這讓程式設計員 可以針對沒有明確標籤的記憶體位址進行存取的動作。 .data arrayW WORD 1000h,2000h,3000h arrayD DWORD 1,2,3,4 .code mov ax,[arrayW+2] ; AX = 2000h mov ax,[arrayW+4] ; AX = 3000h mov eax,[arrayD+4] ; EAX = 00000002h ;下列的陳述必須集合嗎? mov ax,[arrayW-2] ; ?? mov eax,[arrayD+16] ; ?? 當執行的時候會發生什麼事??
換你. . . • Write a program that rearranges the values of three doubleword values in the following array as: 3, 1, 2. • .data • arrayD DWORD 1,2,3 • 步驟1: 將第1個值複製到EAX裡接著在第二個位置交換這個值 mov eax,arrayD xchg eax,[arrayD+4] • 步驟2: Exchange EAX with the third array value and copy the value in EAX to the first array position. xchg eax,[arrayD+8] mov arrayD,eax
評估一下 . . . • 我們想寫一個可以增加下列三個位元組的程式: • .data • myBytes BYTE 80h,66h,0A5h • 你對下列編碼的評估是什麼? • mov al,myBytes • add al,[myBytes+1] • add al,[myBytes+2] • 你對下列編碼的評估是什麼? • mov ax,myBytes • add ax,[myBytes+1] • add ax,[myBytes+2] • 有其他問題??
評估一下 . . . (續) .data myBytes BYTE 80h,66h,0A5h • 下列的編碼怎麼樣?? 有任何的缺少嗎? • movzx ax,myBytes • mov bl,[myBytes+1] • add ax,bx • mov bl,[myBytes+2] • add ax,bx ; AX = sum Yes: 在MOVZX指令之前將0移動至BX暫存器裡
下一章 • 資料轉移指令 • 加法與減法 • 資料相關的運算子和指引 • 間接定址 • JMP和LOOP指令
加法與減法 • INC及DEC指令 • ADD及SUB指令 • NEG指令 • 建立算術運算式 • 算術運算影響的旗標 • 零值旗標 • 符號旗標 • 進位旗標 • 溢位進旗
INC及DEC指令 • INC ( 遞增 ) 和 DEC ( 遞減 ) 指令分別會將其單一運算元加 1 和減 1。 • 運算元也許是暫存器或記憶體 • INC 目的地 • 邏輯: 目的地 目的地+ 1 • DEC 目的地 • 邏輯: 目的地 目地的– 1
INC和DEC範例 .data myWord WORD 1000h myDword DWORD 10000000h .code inc myWord ; 1001h dec myWord ; 1000h inc myDword ; 10000001h mov ax,00FFh inc ax ; AX = 0100h mov ax,00FFh inc al ; AX = 0000h
換你... 在每一個指令執行後,請顯示出目的地運算元的值: .data myByte BYTE 0FFh, 0 .code mov al,myByte ; AL = mov ah,[myByte+1] ; AH = dec ah ; AH = inc al ; AL = dec ax ; AX = FFh 00h FFh 00h FEFF
ADD和SUB指令 • ADD 目的地,來源 • 邏輯: 目的地 目地的+ 來源 • SUB目地的,來源 • Logic: 目的地 目地的– 來源 • 和MOV指令的規則相同
ADD及SUB範例 .data var1 DWORD 10000h var2 DWORD 20000h .code ; ---EAX--- mov eax,var1 ; 00010000h add eax,var2 ; 00030000h add ax,0FFFFh ; 0003FFFFh add eax,1 ; 00040000h sub ax,1 ; 0004FFFFh
NEG (否定)指令 顛倒運算元的符號(即轉變為2’s補數)。 運算元可以是暫存器或記憶體運算元。 .data valB BYTE -1 valW WORD +32767 .code mov al,valB ; AL = -1 neg al ; AL = +1 neg valW ; valW = -32767 假使AX包含 –32,768 並且我們對它執行NEG指令,將會得到一個有效的結果嗎?
NEG指令和旗標 使用NEG指令來執行下面的程式: SUB 0,operand 任何的非零運算元引起要設定的進位旗標 .data valB BYTE 1,0 valC SBYTE -128 .code neg valB ; CF = 1, OF = 0 neg [valB + 1] ; CF = 0, OF = 0 neg valC ; CF = 1, OF = 1
建立算術運算式 HLL 編輯者將數學的表達轉變成組合語言 你也可以做的到.。範例: Rval = -Xval + (Yval – Zval) Rval DWORD ? Xval DWORD 26 Yval DWORD 30 Zval DWORD 40 .code mov eax,Xval neg eax ; EAX = -26 mov ebx,Yval sub ebx,Zval ; EBX = -10 add eax,ebx mov Rval,eax ; -36
換你... 將下面的意思轉換成組合語言。不能變更 Xval, Yval, or Zval : Rval = Xval - (-Yval + Zval) 假設所有的值皆被標示成doublewords. mov ebx,Yval neg ebx add ebx,Zval mov eax,Xval sub eax,ebx mov Rval,eax
算術運算影響的旗標 • ALU有反映算術行動結果的一些狀態旗標。 • 建立目的地運算元的內容 • 必要的旗標: • 零值旗標 – 當目的地等於零的時候設定 • 符號旗標 – 當目的地是負數的時候設定 • 進位旗標 – 當未被標示的值超出範圍時設定 • 溢位旗標 – 當被標示的值超出範圍時設定 • MOV指令不會影響到任何旗標。
觀念圖 CPU 部份 執行 執行 ALU 條件跳躍 算術 & bitwise 操作 附加在 被使用 提拱 影響 狀態旗標 分岐邏輯 你能使用像如此的圖形表達在組合語言觀念之間的關係。
零值旗標 (ZF) 零值旗標是設定於目的地運算元其操作結果為零的時候。 mov cx,1 sub cx,1 ; CX = 0, ZF = 1 mov ax,0FFFFh inc ax ; AX = 0, ZF = 1 inc ax ; AX = 1, ZF = 0 • 記得... • 當它等於1的時候設定旗標。 • 當它等於0的時候清除旗標。
符號旗標 (SF) 符號旗標是設定於目的地運算元其結果為負數的時候。 當其結果為實數時則被清除。 mov cx,0 sub cx,1 ; CX = -1, SF = 1 add cx,2 ; CX = 1, SF = 0 目的運算元的最大有效位元呈現設定 狀態,則符號旗標將呈現設定狀態。 mov al,0 sub al,1 ; AL = 11111111b, SF = 1 add al,2 ; AL = 00000001b, SF = 0
所有CPU指令中,標示與未標示的整數操作完全一構所有CPU指令中,標示與未標示的整數操作完全一構 CPU是無法分辨出是否有標示 你,程式設計師,獨自負責在每個命令使用每個正確的資料類型 標示與未標示的整數硬體的觀念 Added Slide. Gerald Cahill, Antelope Valley College
如何那增加指令和 CF : OF = (MSB 實行) XOR (進入 MSB 之內的進位) CF = (MSB 實行) 附屬的指令如何修正和 CF : NEG 來源而且把它加入目的地 OF = (MSB實行) XOR (進入 MSB 之內的進位) CF = INVERT (MSB實行) 溢位及進位旗標硬體觀念 MSB = 最大有效位元 XOR =互斥邏輯閘 NEG =否定
進位旗標 (CF) 進位旗標可以指出無號整數的溢位狀態 (目地的運算元太大或太小) mov al,0FFh add al,1 ; CF = 1, AL = 00 ; Try to go below zero: mov al,0 sub al,1 ; CF = 1, AL = FF
換你 . . . 從下列程式中,表示出目的地運算位的值、符號旗標的值、零值旗標的值、進位旗標的值 mov ax,00FFh add ax,1 ; AX= SF= ZF= CF= sub ax,1 ; AX= SF= ZF= CF= add al,1 ; AL= SF= ZF= CF= mov bh,6Ch add bh,95h ; BH= SF= ZF= CF= mov al,2 sub al,3 ; AL= SF= ZF= CF= 0100h 0 0 0 00FFh 0 0 0 00h 0 1 1 01h 0 0 1 FFh 1 0 1
溢位旗標 (OF) 當有號數算術運算的結果使目的運算元溢位或欠位時,溢位旗 標將呈現設定狀態 ; Example 1 mov al,+127 add al,1 ; OF = 1, AL = ?? ; Example 2 mov al,7Fh ; OF = 1, AL = 80h add al,1 這兩個範例在二進位的標準是相同的,因為7Fh等於+127。 要決定目的地運算元的值,在十六進位中通常是比較容易去計算的。
概略的做法 • 當要增加二個整數時,記得溢位旗標只設定在… • 兩個正值運算元在相加後的總數是負數時 • 兩個負值運算元在相加後的總數是正數時 溢位旗標的值是多少? mov al,80h add al,92h ; OF = mov al,-2 add al,+127 ; OF = 1 0
換你 . . . 在執行後給定旗標的值是多少? mov al,-128 neg al ; CF = OF = mov ax,8000h add ax,2 ; CF = OF = mov ax,0 sub ax,2 ; CF = OF = mov al,-5 sub al,+125 ; OF = 1 1 0 0 1 0 1
下一章 • 資料轉移指令 • 加法與減法 • 資料相關的運算子和指引 • 間接定址 • JMP和LOOP指令
資料相關的運算子和指引 • OFFSET運算子 • PTR運算子 • TYPE運算子 • LENGTHOF運算子 • SIZEOF運算子 • LABEL指引
OFFSET運算子 • OFFSET 運算子會回傳資料標籤的位移。位移代表的是標籤到資料區段起始點的距離,其 單位是位元組。 • 在保護模式下位移有 32 位元 • 在實體位址模式下位移只有 16 位元 在保護模式下的程式我們只有撰寫一部份 (我們使用的是平坦式記憶體模式)
OFFSET範例 讓我們假定資料部份從00404000h 開始: .data bVal BYTE ? wVal WORD ? dVal DWORD ? dVal2 DWORD ? .code mov esi,OFFSET bVal ; ESI = 00404000 mov esi,OFFSET wVal ; ESI = 00404001 mov esi,OFFSET dVal ; ESI = 00404003 mov esi,OFFSET dVal2 ; ESI = 00404007
Relating to C/C++ 被OFFSET送回的的值是一個指標。 比較C++語言寫的編碼和程式語言寫的編碼: ; C++ 版本: char array[1000]; char * p = array; .data array BYTE 1000 DUP(?) .code mov esi,OFFSET array ; ESI is p
PTR運算子 使用 PTR 運算子,來置換一個運算元已被宣告的空間大小值。 這只有在你想要 存取的變數的空間大小屬性與當初宣告該變數的大小屬性不同時才須要用到。 .data myDouble DWORD 12345678h .code mov ax,myDouble ; error – why? mov ax,WORD PTR myDouble ; loads 5678h mov WORD PTR myDouble,4321h ; saves 4321h 當儲存資料在記憶的時候,小 endian 次序被使用的取消(參考第3.4.9節)。
小 Endian 次序 • 小 endian 次序提及英代爾在記憶儲存整數的方式. • 多位元組整數被儲存在反面的次序中,藉由被儲存在最低的位址的最沒有重要的位元組 • 舉例來說, doubleword 12345678h 將會被儲存當做: 當整數從記憶到暫存器被裝載的時候,位元組再自動地進入他們的正確位置之內被顛倒.
PTR運算子範例 .data myDouble DWORD 12345678h mov al,BYTE PTR myDouble ; AL = 78h mov al,BYTE PTR [myDouble+1] ; AL = 56h mov al,BYTE PTR [myDouble+2] ; AL = 34h mov ax,WORD PTR myDouble ; AX = 5678h mov ax,WORD PTR [myDouble+2] ; AX = 1234h
PTR運算子(續) PTR 也能用來結合一個更小的資料類型的要素並且移動他們進入一個更大的運算元之內。 CPU必須自動的顛倒位元組。 .data myBytes BYTE 12h,34h,56h,78h .code mov ax,WORD PTR [myBytes] ; AX = 3412h mov ax,WORD PTR [myBytes+2] ; AX = 7856h mov eax,DWORD PTR myBytes ; EAX = 78563412h
換你 . . . 寫下每個目的地運算元的值: .data varB BYTE 65h,31h,02h,05h varW WORD 6543h,1202h varD DWORD 12345678h .code mov ax,WORD PTR [varB+2] ; a. mov bl,BYTE PTR varD ; b. mov bl,BYTE PTR [varW+2] ; c. mov ax,WORD PTR [varD+2] ; d. mov eax,DWORD PTR varW ; e. 0502h 78h 02h 1234h 12026543h
TYPE運算子 TYPE 運算子會回傳變數的單一元素的大小,其單位是位元組。 .data var1 BYTE ? var2 WORD ? var3 DWORD ? var4 QWORD ? .code mov eax,TYPE var1 ; 1 mov eax,TYPE var2 ; 2 mov eax,TYPE var3 ; 4 mov eax,TYPE var4 ; 8
LENGTHOF運算子 LENGTHOF 運算子會計算陣列中的元素數目,而此數目是由與標籤位於同一行的若干個 值所定義。 .data LENGTHOF byte1 BYTE 10,20,30 ; 3 array1 WORD 30 DUP(?),0,0 ; 32 array2 WORD 5 DUP(3 DUP(?)) ; 15 array3 DWORD 1,2,3,4 ; 4 digitStr BYTE "12345678",0 ; 9 .code mov ecx,LENGTHOF array1 ; 32