《匯編語言:基于X86處理器》第6章 條件處理(2)

本章向程序員的匯編語言工具箱中引入一個重要的內容,使得編寫出來的程序具備作決策的功能。幾乎所有的程序都需要這種能力。首先,介紹布爾操作,由于能影響CPU狀態標志,它們是所有條件指令的核心。然后,說明怎樣使用演繹CPU狀態標志的條件跳轉和循環指令。接著演示如何用本章介紹的工具來實現理論計算機科學中最根本的結構之一:有限狀態機。本章最后展示的是MASM內置的32位編程的邏輯結構。

6.4 條件循環指令

6.4.1 LOOPZ和 LOOPE 指令

LOOPZ(為零跳轉)指令的工作和LOOP指令相同,只是有一個附加條件:為零控制轉向目的標號,零標志位必須置1。指令語法如下:

LO0PZ destination

LOOPE(相等跳轉)指令相當于LOOPZ,它們有相同的操作碼。這兩條指令執行如下任務:

ECX=ECX-1

if ECX > 0 and F =1, jump to destination

否則,不發生跳轉,并將控制傳遞到下一條指令。LOOPZ和LOOPE不影響任何狀態標志位。32位模式下,ECX是循環計數器;64位模式下,RCX是循環計數器。

完整代碼測試筆記

;6.4.1.asm  LOOPNZ指令 和LOOPNE指令用法學習
;找出數組中第1個小寫字母.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
array WORD 'A', 'C', 'S',  'P', 'a', 'y', 'h', 'x'
value WORD 0.code
main PROCmov ecx, LENGTHOF arraymov esi, 0
L1:test array[esi], 00100000b					;無符號數比較,影響零標志和進位標志pushfdadd esi, TYPE arraypopfdloopz L1sub esi, TYPE arraymov ax,  WORD PTR array[esi]mov value, axINVOKE ExitProcess,0
main ENDP
END main

運行調試

6.4.2 LOOPNZ和 LOOPNE 指令

LOOPNZ(非零跳轉)指令與LOOPZ相對應。當ECX中無符號數值大于零(減1操作之后)且零標志位等于零時,繼續循環。指令語法如下:

LOOPNZ destination

LOOPNE(不等跳轉)指令相當于LOOPNZ,它們有相同的操作碼。這兩條指令執行如下任務:

ECX=ECX-1

if ECX > 0 and F =0, jump to destination

否則,不發生跳轉,并將控制傳遞到下一條指令。

完整代碼測試筆記:

;6.4.2.asm  LOOPNZ指令 和LOOPNE指令學習
;與Loopnz.asm功能一樣.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
array SWORD -1, -6, -1, -10, 10, 30, 40, 4
sentinel SWORD 0.code 
main PROCmov esi, OFFSET arraymov ecx, LENGTHOF array
L1:	test WORD PTR [esi], 8000h			;測試符號位,該指令影響符號標志,零標志,奇偶標志jns quit												;無符號跳轉(表示非負數)add esi,TYPE array							;移動到下一個位置loopnz L1												;繼續循環jnz notFind											;沒有發現非負數
quit:movzx eax, WORD PTR[esi]mov sentinel, ax
notFind:nopINVOKE ExitProcess,0main ENDP 
END main

運行調試:

如果找到一個非負數,ESI會指向該數值。如果沒有找到一個正數,則只有當ECX=0時才終止循環。在這種情況下,JNZ指令跳轉到標號quit,同時ESI指向標記值(0),其在內存中的位置正好緊接著該數組。

6.4.3 本節回顧

1.(真/假):當(且僅當)零標志位被清除時,LOOPE指令跳轉到標號

答:假。當ZF=1并且ECX > 0時才跳轉

2.(真/假):32位模式下,當ECX大于零且零標志位被清除時,LOOPNZ指令跳轉到標號。

答:真。

3.(真/假):LOOPZ指令的目的標號必須處在距離其后指令的-128到+127字節范圍之內。

答:真

4.修改6.4.2節中的LOOPNZ示例,使之掃描數組并搜索其中的第一個負數。改變數組的初始化,用正數作為其起始值。

答:修改后的代碼如下

;6.4.3_4.asm   6.4.3 本節回顧      4.修改6.4.2節中的LOOPNZ示例,  
;使之掃描數組并搜索其中的第一個負數。改變數組的初始化,用正數作為其起始值。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
array SWORD 10, 30, 40, 4, -56, -17, -98
sentinel SWORD 0.code 
main PROCmov esi, OFFSET arraymov ecx, LENGTHOF array
L1:	test WORD PTR [esi], 8000h			;測試符號位,該指令影響符號標志,零標志,奇偶標志pushfd							;標志位入棧add esi,TYPE array				;移動到下一個位置popfd						    ;標志位出棧loopz L1						;繼續循環jz quit							;沒有發現負數sub esi, TYPE array				;ESI指向數值
quit:movzx eax, WORD PTR[esi]mov sentinel, axINVOKE ExitProcess,0main ENDP 
END main

運行調試:

5.挑戰:6.4.2節的LOOPNZ示例依靠一個標記值來處理沒有發現正數的可能性。如果把這個標記值去掉,會發生什么?

答:如果沒有發現匹配值,ESI將以指向數組末層之外作為結束。若指向了一個未定義的內存位置,那么程序運行就可能導致運行時錯誤。

6.5 條件結構

條件結構被定義為,能夠在不同的邏輯分支中觸發選擇的一個或多個條件表達式。每一個分支都執行不同的指令序列。毫無疑問,在高級編程語言中已經使用了條件結構,但是你可能并不了解語言編譯器是如何將條件結構轉換為低級機器代碼的。現在就來討論這個轉換過程.

6.5.1 塊結構的 IF 語句

IF結構包含一個布爾表達式,其后有兩個語句列表:一個是當表達式為真時執行,另一個是當表達式為假時執行:

if(boolean - expression)statement - list - 1
elsestatement - list - 2

結構中的else部分是可選的。在匯編語言中,則是用多個步驟來實現這種結構的。首先,對布爾表達式求值,這樣一來某個CPU狀態標志位會受到影響。然后,根據相關CPU狀態標志位的值,構建一系列跳轉把控制傳遞給兩個語句列表。

示例1下面的C++代碼中,如果op1等于op2,則執行兩條賦值語句:

if(op1 == op2) 
{X = 1;Y = 2;
}

在匯編語言中,這種正語句轉換為條件跳轉和CMP指令。由于op1和op2都是內存操作數(變量),因此,在執行CMP之前,要將其中的一個操作數送人寄存器。下面實現IF語句的程序是高效的,當邏輯表達式為真時,它允許代碼“通過”直達兩條期望被執行的MOV 指令:

;6.5.1_1.asm      塊結構的 IF 語句       示例1 用匯編語言實現下面c++語句
;if(op1 == op2)  {
;		X = 1;
;		Y = 2;
;}.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
op1 DWORD 45
op2 DWORD 45
X DWORD ?
Y DWORD ?.code 
main PROC;1.jne的方式。它允許代碼“通過”直達兩條期望被執行的MOV 指令:
;		mov eax, op1
;		cmp eax, op2								;op1 == op2 ?
;			jne L1									;否:跳過后續指令
;			mov X, 1								;是:X,Y賦值
;			mov Y, 2
;			jmp quit
;L1:	mov X, 10
;			mov Y, 20;2.je的方式。用正來實現==運算符,生成的代碼就沒有那么緊湊了(6條指令,而非5條指令):mov eax, op1cmp eax, op2								; op1 == op2 ?je L1										;是:跳轉到L1jmp L2										;否:跳過賦值語句
L1:	mov X, 1										;X,Y賦值mov Y, 2									jmp quit
L2:	mov X, 10									mov Y, 20									
quit:nopINVOKE ExitProcess,0main ENDP 
END main

方式1調試:

方式2調試:

從上面的例子可以看出,相同的條件結構在匯編語言中有多種實現方法。本章給出的編譯代碼示例只代表一種假想的編譯器可能產生的結果

示例2? NTFS文件存儲系統中,磁盤簇的大小取決于磁盤卷的總容量。如下面的偽代碼所示,如果卷大小(用變量terrabytes存放)不超過16TB,則簇大小設置為4096。否則簇大小設置為8192

clustersize=8192
if terrabytes <16clusterSize = 4096:

用匯編語言實現該偽代碼:

;6.5.1_2.asm      塊結構的 IF 語句       示例2  用匯編語言實現下面語句
;clustersize = 8192
;if terrabytes < 16
;  clusterSize = 4096:.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
clusterSize WORD ?								;簇大小
terrabytes WORD 1								;磁盤卷大小,單位TB.code 
main PROCmov clusterSize, 8192					;假設較大的磁盤簇cmp terrabytes, 16						;小于16TB ?jae next								;大于或等于跳轉								mov clusterSize, 4096					;切換到較小的磁盤簇
next:	nopINVOKE ExitProcess,0main ENDP 
END main

運行調試:

示例3 下面的偽代碼有兩個分支:

if op1 > op2call Routine1
elsecall Routine2
end if

用匯編語言翻譯這段偽代碼,設op1和op2是有符號雙字變量。對這兩個變量比較時其中一個必須送入寄存器:

;6.5.1_3.asm      塊結構的 IF 語句       示例3  用匯編語言實現下面語句
;if op1 > op2
;	call Routine1
;else
;	call Routine2
;end if.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
op1 DWORD 55
op2 DWORD 51.code 
main PROCmov eax, op1									;op1送入寄存器cmp eax, op2									;op1 >op2?jg A1											;是:調用 Routine1call Routine2									;否:調用 Routine2jmp A2											;退出IE語句
A1:	call Routine1									
A2:	nopINVOKE ExitProcess,0
main ENDP Routine1 PROCmov edx, op1ret
Routine1 ENDPRoutine2 PROCmov edx, op2ret
Routine2 ENDP
END main

運行調試:

白盒測試

復雜條件語句可能有多個執行路徑,這使得它們難以進行調試檢查(查看代碼)。程序員經常使用的技術稱為白盒測試,用來驗證子程序的輸入和相應的輸出。白盒測試需要源代碼,并對輸人變量進行不同的賦值。對每個輸入組合,要手動跟蹤源代碼,驗證其執行路徑和子程序產生的輸出。下面,通過嵌套正語句的匯編程序來看看這個測試過程:

if op1 == op2if X > Ycall Routine1elsecall Routine2
elsecall Routine3
end if

下面是可能的匯編語言翻譯,加上了參考行號。程序改變了初始條件(op1=-op2),并立即跳轉到 ELSE部分。剩下要翻譯的內容是內層IF-ELSE 語句:

    mov eax, op1				cmp eax, op2				;op1 == op2 ?jne L2						;否:調用Routine3,  不等于跳轉到L2mov eax, X					;處理內層IF-ELSE 語句cmp eax, Y					;X > Y ?jg L1						;是:調用 Routine1,   大于跳轉到L1  call Routine2				;否:調用 Routine2jmp L3						;退出
L1:	call Routine1				;調用 Routine1jmp L3						;退出
L2:	call Routine3
L3:	

表6-6給出了示例代碼的白盒測試結果。前四列對op1、op2、X和Y進行測試賦值。

第5列和第6列對生成的執行路徑進行了驗證

6.5.2 復合表達式

匯編語言很容易實現包含AND運算符的復合布爾表達式。考慮下面的偽代碼,假設其中進行比較的是無符號整數:

if (al > bl) AND (bl > cl)X = 1
else if

短路求值 下面的例子是短路求值的簡單實現,如果第一個表達式為假,則不需計算第二個表達式。高級語言的規范如下:

;6.5.2_1.asm      復合表達式       1.邏輯 AND 運算符
;if (al > bl) AND (bl > cl)  
;		X = 1;
;end if.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
X BYTE 23.code 
main PROCmov al, 5mov bl, 4mov cl, 3;方式1cmp al, bl							;第一個表達式…ja L1								;大于跳轉到L1jmp next							;否則退出if
L1:	cmp bl, cl								;第二個表達式…ja L2								;大于跳轉到L2jmp next							;否則退出if
L2:	mov X, 1								;全為真:將X置1
next:jmp quit;方式2,    如果把第一條 JA指令替換為JBE,就可以把代碼減少到5條:cmp al, bl							;第一個表達式…jbe quit							;如果假,則退出    小于或等于跳轉到quit,退出if, jbe無符號比較cmp bl, cl							第二個表達式…jbe quit							;如果假,則退出    小于或等于跳轉到quit,退出if, jle有符號比較mov X, 1							;全為真
quit: nopINVOKE ExitProcess,0main ENDP 
END main

運行調試

方式1:

方式2:

若第一個JBE不執行,CPU可以直接執行第二個CMP指令,這樣就能夠減少29%的代碼量(指令數從7條減少到5條)。

2.邏輯 OR 運算符

當復合表達式包含的子表達式是用OR運算符連接的,那么只要一個子表達式為真,則整個復合表達式就為真。以如下偽代碼為例:

if (al > bl) OR (bl > cl)X = 1

在下面的實現過程中,如果第一個表達式為真,則代碼分支到L1;否則代碼直接執行第二個CMP指令。第二個表達式翻轉了>運算符,并使用了JBE指令:

【代碼】

對于一個給定的復合表達式而言,匯編語句有多種實現方法。

2.邏輯 OR 運算符

當復合表達式包含的子表達式是用OR運算符連接的,那么只要一個子表達式為真,則整個復合表達式就為真。以如下偽代碼為例:

if (al > bl) OR (bl > cl)X = 1

在下面的實現過程中,如果第一個表達式為真,則代碼分支到L1;否則代碼直接執行第二個CMP指令。第二個表達式翻轉了>運算符,并使用了JBE指令:

;6.5.2_2.asm      復合表達式       2.邏輯 OR 運算符
;if (al > bl) OR (bl > cl)  
;		X = 1;.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
X BYTE 23.code 
main PROCmov al, 2mov bl, 4mov cl, 3cmp al, bl							;1:比較AL和 BLja L1										;如果真,跳過第二個表達式cmp bl, cl							;2:比較BL和CLjbe next								;假:跳過下一條語句
L1:	mov X, 1								;真:將X置1
next: nopINVOKE ExitProcess,0main ENDP 
END main

運行調試:

對于一個給定的復合表達式而言,匯編語句有多種實現方法。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/89466.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/89466.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/89466.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深度剖析NumPy核心函數reshape()

深度剖析NumPy核心函數reshape reshape()函數基礎概念reshape()函數語法與參數詳解reshape()函數使用示例基本的形狀重塑使用-1自動計算維度多維數組的形狀重塑不同order參數的效果 reshape()函數的應用場景數據預處理機器學習模型輸入算法實現 當我們使用np.array()創建好數組…

Linux平臺MinGW32/MinGW64交叉編譯完全指南:原理、部署與組件詳解

一、MinGW是什么&#xff1f;為什么需要交叉編譯&#xff1f; MinGW&#xff08;Minimalist GNU for Windows&#xff09;是一套在Linux上構建Windows應用程序的完整工具鏈。它允許開發者&#xff1a; 在Linux環境下編譯Windows可執行文件&#xff08;.exe/.dll&#xff09;避…

為什么我畫的頻譜圖和audacity、audition不一樣?

文章目錄 系列文章目錄 目錄 文章目錄 前言 一、問題引入 二、使用步驟 三、分析和改進 總結 前言 我們知道audacity和audition都有頻譜分析這個窗口&#xff0c;一般過程肯定是分幀加窗&#xff0c;fft變換然后呈現&#xff0c; 大體這個過程是沒問題的&#xff0c;但為什…

責任鏈模式 Go 語言實戰

責任鏈模式&#xff08;Chain of Responsibility&#xff09; 責任鏈模式是一種行為設計模式&#xff0c;它允許將請求沿著處理者鏈進行傳遞&#xff0c;直到有一個處理者能夠處理它。這個模式的主要目的是解耦請求的發送者和接收者&#xff0c;使得多個對象都有機會處理這個請…

使用開源項目youlai_boot 導入到ecplise 中出現很多錯誤

我是使用ecplise 導入得youlai_boot 這個項目&#xff0c;但是導入到ecplise 中一直出現報錯&#xff0c;然后各種maven clean 和maven install 以及update Maven 都沒有效果不知道怎么辦才好&#xff0c;怎么樣解決這個問題&#xff0c;原來是我本地的環境中沒有安裝 lombok.…

06_Americanas精益管理項目_數據分析

文章目錄 Americanas精益管理項目_數據分析(一)思維方法1、數據分析思維2、零售行業-萬能「人貨場」分析框架(二)商品分析1、品類銷量分析2、銷量趨勢分析3、帕累托法則分析4、商品TopN分析(三)用戶分析(四)場景分析Americanas精益管理項目_數據分析 數據分析與數據開…

ES6從入門到精通:類與繼承

ES6 類的基本概念 ES6 引入了基于類的面向對象編程語法&#xff0c;通過 class 關鍵字定義類。類可以包含構造函數、方法和屬性。 class Person {constructor(name) {this.name name;}greet() {console.log(Hello, ${this.name}!);} }const person new Person(Alice); pers…

【經驗】新版Chrome中Proxy SwitchyOmega2已實效,改為ZeroOmega

1、問題描述 手欠更新了 Chrome 導致無法“上網”&#xff0c;原因是 Proxy SwitchyOmega2 已實效。 2、解決方法 2.1 下載 新版Chrome中Proxy SwitchyOmega2已實效&#xff0c;改為ZeroOmega&#xff1b; 想方設法去下載 ZeroOmega 的crx包&#xff0c;最新的為&#xff1…

在windows上設置python的環境

安裝好了python,再具體說下python語言的相關環境。 #01 關于Python Python 是一個高級別的、邊運行邊解釋的、動態類型的編程語言,以簡潔的語法、強大的功能和豐富的資源庫而聞名。廣泛應用于 Web 開發、數據分析、人工智能、自動化腳本等多個領域。 目前 Python 語言有兩…

3D 建模與點云建模:從虛擬構建到實景復刻的數字孿生雙引擎

在數字化浪潮席卷全球的當下&#xff0c;3D 建模與點云建模如同數字世界的左膀右臂&#xff0c;一個以抽象化的創意構建虛擬藍圖&#xff0c;一個以高精度的實景數據復刻現實世界。它們不僅深刻重塑了影視娛樂、工業制造、建筑設計等傳統領域&#xff0c;更成為數字孿生技術蓬勃…

智能檢測原理和架構

大家讀完覺得有幫助記得關注和點贊&#xff01;&#xff01;&#xff01; 智能檢測系統基于AI和大數據分析技術&#xff0c;通過主動感知、行為建模與實時響應構建動態防御體系。其核心在于將傳統規則匹配升級為**多模態威脅認知**&#xff0c;實現對新型攻擊&#xff08;如AI…

2025年6月個人工作生活總結

本文為 2025年6月工作生活總結。 研發編碼 某國產操作系統curl下載sftp服務器文件問題記錄 場景&#xff1a; 某國產系統curl版本信息&#xff1a; # curl --version curl 7.71.1 (x86_64-koji-linux-gnu) libcurl/7.71.1 OpenSSL/1.1.1f-fips zlib/1.2.11 brotli/1.0.7 li…

Java 導出PDF 1、內容可以插入自定義表格 2、內容插入圖片

Java PDF導出工具&#xff1a;自定義表格與圖片插入 下面我將實現一個Java PDF導出工具&#xff0c;支持插入自定義表格和圖片的功能。這個解決方案使用iText 7庫&#xff0c;提供了一個直觀的用戶界面&#xff0c;可以預覽生成的PDF內容。 import javax.swing.*; import jav…

sklearn機器學習概述及API詳細使用指南

一、機器學習與sklearn簡介 機器學習是人工智能的一個分支&#xff0c;它通過算法讓計算機從數據中學習規律&#xff0c;并基于這些規律做出預測或決策。scikit-learn&#xff08;簡稱sklearn&#xff09;是Python中最流行的機器學習庫之一&#xff0c;它提供了各種監督學習和…

「日拱一碼」015 機器學習常用庫——scikit-learn

目錄 數據預處理 數據標準化&#xff08;StandardScaler&#xff09; 數據歸一化&#xff08;MinMaxScaler&#xff09; 數據離散化&#xff08;KBinsDiscretizer&#xff09; 缺失值處理&#xff08;SimpleImputer&#xff09; 特征選擇 基于單變量特征選擇&#xff08…

網絡編程學習路線

C網絡編程從零基礎到精通的學習路線&#xff0c;每一步都和你的項目實際需求緊密結合&#xff0c;幫助你真正做到“學以致用”。 C網絡編程學習路線&#xff08;結合FileHub項目&#xff09; 第一階段&#xff1a;網絡編程基礎入門 1. 計算機網絡基礎 理解OSI七層模型、TCP/I…

NLP:文本張量表示方法

本文目錄&#xff1a; 一、one-hot編碼二、word2vec模型&#xff08;一&#xff09;概念1.CBOW(Continuous bag of words)模式2.skipgram模式:3.詞向量的檢索獲取 &#xff08;二&#xff09;word2vec的訓練和使用1. 獲取訓練數據2.查看原始數據3.原始數據處理&#xff0c;并查…

高階數據結構------并查集

并查集 在一些應用問題中&#xff0c;需要將n個不同的元素劃分成一些不相交的集合。開始時&#xff0c;每個元素自成一個集合&#xff0c;然后按照一定的規律將歸于同一組的元素集合合并。在此過程中要反復用到查詢某一個元素歸屬于哪一個集合的運算。適合于描述這類問題的抽象…

OWASP Top 10 是什么?

OWASP&#xff08;Open Web Application Security Project&#xff0c;開放Web應用安全項目&#xff09;是一個致力于提高軟件安全性的國際非營利組織。其發布的 ?OWASP Top 10? 是最具影響力的Web應用安全風險清單&#xff0c;每3-4年更新一次&#xff0c;幫助開發人員、安全…

如何在IIS上部署net系統(安裝iis參考上一篇)

1.對后端項目打包&#xff0c;我使用的時rider 2.打包前端 npm run build 3.在iis上部署 網站-添加網站 4.選擇之前打包的后端文件&#xff0c;設置端口 5.安裝對應net環境插件&#xff1a;主要是runtime和sdk插件以及dotnet-hosting-2.2.0-win&#xff0c;具體版本看自己項…