8086彙編語言學習(二) 8086彙編開發環境搭建和Debug模式介紹

来源:https://www.cnblogs.com/xiaoxiongcanguan/archive/2020/01/16/12176857.html
-Advertisement-
Play Games

1. 8086彙編開發環境搭建 在上篇博客中簡單的介紹了8086彙編語言。工欲善其事,必先利其器,在8086彙編語言正式開始學習之前,先介紹一下如何搭建8086彙編的開發環境。 彙編語言設計之初是用於在沒有操作系統的裸機上直接操作硬體的,但對於大部分人來說,在8086裸機上直接進行編程將會面臨各種困 ...


1. 8086彙編開發環境搭建

  在上篇博客中簡單的介紹了8086彙編語言。工欲善其事,必先利其器,在8086彙編語言正式開始學習之前,先介紹一下如何搭建8086彙編的開發環境。

  彙編語言設計之初是用於在沒有操作系統的裸機上直接操作硬體的,但對於大部分人來說,在8086裸機上直接進行編程將會面臨各種困難。好在我們可以使用軟體模擬器來模擬硬體進行8086的學習實踐。在《彙編語言》中作者推薦通過windows環境下的masmdebug進行學習。

masm介紹:

  masm是一款DOS下的彙編工具包,在8086彙編的學習中我們需要其中的幾個文件,分別是masm.exelink.exe

  masm.exe 彙編器,用於將文本格式的彙編語言源文件編譯為.obj結尾的二進位文件,其生成的.obj結尾的二進位目標文件是被編譯的源文件的對應的機器碼。單獨的源程式目標文件通常是無法直接運行的,還需要和互相依賴的其它同樣編譯完成的二進位文件鏈接在一起才能生成最終的可執行文件(比如所需要的靜態庫函數) 。因此,obj文件通常也被叫做中間文件。

  link.exe 鏈接器,obj文件需要通過鏈接才能轉換成可執行程式,而鏈接器就是負責完成這一任務的。鏈接器能將多個obj目標文件以及其所依賴的庫程式進行統一處理(例如多個目標文件中指令、數據記憶體地址的偏移處理),並生成可執行文件。

debug介紹:

  debug.exe 調試器,windows提供了一個在dos中調試8086彙編程式的工具debug.exe,提供了展示程式運行時CPU中各寄存器、記憶體中數據指令級的單步調試等功能。debug程式的使用會在本篇博客的後半段進行詳細介紹。

64位操作系統相容性問題:

  由於《彙編語言》一書出版較早,當時的windows系統還是32位的,32位windows系統都預設安裝了masm與debug,能打開dos視窗直接使用。但目前普遍使用的、新的windows 64位操作系統中卻並沒有預設提供masm工具包和debug.exe,同時masm、debug也與64位的windows系統版本不相容。

想在64位的windows系統下使用masm、debug有兩個常用方法:

  1. 通過虛擬機安裝一個老版本的windows操作系統(推薦windows xp)

  2. 通過DOSBox這一輕量級的ms-dos模擬器來運行,但上文所述的依賴程式需單獨下載(百度網盤下載鏈接:https://pan.baidu.com/s/158NKJoea6_Y4UmCFsDP0oQ#list/path=%2F)

  個人推薦第二種方法,下麵介紹如何在windows64位操作系統下使用DOSBox來搭建8086彙編語言的開發環境。

DOSBox安裝與使用

DOSBox下載安裝:

  DOSBox可以在官網下載,這裡也提供了百度網盤的下載鏈接(0.74版本):https://pan.baidu.com/s/11_GcPpTqJm78N8xEXZpPMw

  安裝完畢後,找到安裝目錄下的DOSBox.exe並啟動,能看到如下圖界面。

  

  作為dos的模擬器和普通的dos視窗沒有明顯區別,但是初始時並不能直接訪問到本地磁碟,需要先將本地磁碟掛載到DOSBox中

DOSBox掛載本地磁碟:

  1. 在本地操作系統磁碟上選擇一個文件夾目錄,作為掛載的磁碟路徑(例如C:\dos)

  2. 在DOSBox啟動的dos視窗中執行命令:mount C C:\dos(代表著將本地的C:\dos路徑掛載到DOSBox的C盤路徑下),能把dos視窗的工作目錄切換到C盤,接下來就可以正常訪問被掛載的磁碟路徑下的內容了。

  3. 將前面提到過的debug.exe等文件都放在這個掛載的本地磁碟路徑下(例如C:\dos),通過DOSBox就可以相容的運行masm工具包中的程式和debug.exe了

  

添加自動執行腳本以避免重覆操作:

  由於上述DOSBox的磁碟掛載是臨時的,每次重新啟動DOSBox後都需要重新輸入命令進行掛載,太麻煩了。我們可以通過修改DOSBox配置的方式,免去這些重覆的操作。

  找到DOSBox安裝目錄下的DOSBox 0.74 Options.bat,使用系統自帶的記事本直接打開,暫不研究其它配置段的作用,找到最後的【autoexec】段,配置在【autoexec】的內容會作為命令在DOSBox啟動時按順序被自動執行。  

  將掛載磁碟操作命令配置在【autoexec】段中能避免重覆操作。修改並保存配置文件後,重新啟動DOSBox,發現配置中添加的命令會被自動執行。

  

2. 8086debug模式介紹

  在搭建好了8086彙編的開發環境後,接下來介紹8086的debug模式。執行debug.exe以進入debug調試模式,在dos中通過輸入命令的方式進行交互。

  

  debug模式下有20多種不同命令,限於篇幅這裡只會介紹幾個以後實驗時常用到的命令。(通過回車執行命令,DOS下的命令預設是不區分大小寫的)

R命令 查看/改變CPU寄存器內容

  R命令的作用是查看和修改debug模式下CPU中寄存器的值。

  (-r) 單獨的輸入r,可以查看當前CPU的內容

  (-r 寄存器名) r加上寄存器名可以在接下來的":"提示後輸入新的值,以達到修改對應寄存器內容的目的(示例中第二行 AX 0000表示修改前寄存器AX的值為0000)  

D命令 查看記憶體中的內容

  D命令的作用是查看記憶體中的內容。

  D命令有許多不同的傳參方式可供使用,先介紹最易理解的(段地址:偏移地址)查看方式。D命令預設會顯示定址地址開始的後128個記憶體單元的內容,以16進位的方式顯示(每個記憶體單元8位,一行最多16個記憶體單元),而最右邊會將記憶體單元中的二進位數據以ascll碼的形式翻譯展示。

  

  有時,我們只想聚焦於某一部分記憶體地址的內容,而預設展示的記憶體視圖不是很方便。

  D命令提供了另外一種訪問記憶體的方式(段地址:偏移起始地址 偏移終止地址),其能夠展示(段地址:偏移起始地址 至 段地址:偏移終止地址)的記憶體信息,範圍兩端均為閉區間。

  

E命令 改變記憶體中的內容

  E命令的作用是改變記憶體中的內容

  和對CPU中寄存器的查看,修改不同,對記憶體進行查看和修改較為複雜,為此debug設計了兩個不同的命令分別進行控制(E命令修改記憶體、D命令查看記憶體)。

  通過(E 起始地址 數據1 數據2 數據3...)命令可以修改記憶體中以起始地址開始,順序的N個記憶體單元的值(N為實際參數傳遞的數量)。

  

   也可以和R命令修改CPU中寄存器值類似的,通過提示來修改特定記憶體單元的值。00.12  00代表記憶體單元在修改前的值,12是我們手動輸入的、需要修改的新值。

  

  可以通過E命令向記憶體輸入對應的機器指令,因為機器指令也是數據的一種

有以下指令(左側為機器碼,右側為對應的彙編指令):

  B80100  mov ax,0001

  BB0200  mov bx,0002

  01D8      add ax,bx

  我們可以向記憶體1000:0處寫入這些機器指令,以供接下來通過debug執行這段機器指令 (執行命令:E 1000:0 B8 01 00 BB 02 00 01 D8)。

  

U命令 將記憶體數據轉換為彙編指令展示

  U命令的作用是將記憶體中的二進位數據轉換為彙編指令展示(反彙編)。

  D命令能夠將記憶體中的數據以16進位或ascll碼的形式展現出來,但有時我們需要觀察的是記憶體中的機器指令時,D命令的視圖過於抽象,不利於理解。debug提供了U命令來解決這個問題。

  對於前面我們在1000:0處輸入的機器指令,使用 U 1000:0 命令(u 記憶體地址)可以將記憶體中的數據以彙編語言指令的方式進行展示。

  

  可以觀察到,左邊展示的是記憶體地址,中間則是16進位的記憶體視圖,右邊展示的是記憶體中數據所對應的彙編指令(例如: 1000:0000B80100MOV AX,0001)。

  由於我們只輸入了三條彙編指令,而後面記憶體中的數據並不是我們想要執行的,但U命令卻依然將其以彙編指令的形式轉換並顯示出來了。

  這也是前一篇博客所提到的,記憶體中的數據完全是二進位的,既可以將其看做普通的二進位數據、十六進位數據、ascll碼文本數據,也可以視作程式指令,這些二進位的"數據"的處理完全取決於如何對其進行解釋

T命令 單步執行機器指令

  T命令的作用是進行單步機器指令的調試

  以上文通過E命令寫入記憶體1000:0的三條指令舉例,介紹如何使用T命令來讓CPU執行1000:0處的機器指令。T命令用於單步調試,一次只會執行一條機器指令。

  8086CPU在運行時會將CS:IP寄存器所指向的記憶體單元中的內容解釋為指令執行,要將記憶體1000:0處的內容作為指令執行必須先修改CS、IP兩個寄存器的值,使之指向1000:0。

  

   先執行一次T命令,1000:0處的指令(mov ax,0001)便會被執行,可以觀察到寄存器ax的值已經變成了0001;同時寄存器IP的值增加了3(mov ax,0001的指令長度為3),此時CS:IP指向的便是位於1000:3處的下一條指令(mov bx,0002),在視圖的最後一行中也有所體現

   

   再執行一次T命令,會執行1000:3處的指令(mov bx,0002),可以觀察到寄存器bx的值變成了0002;寄存器IP的值又增加了3(mov bx,0002的指令長度也是3),此時CS:IP指向的便是位於1000:6處的下一條指令(add ax,bx)

  

  最後執行一次T命令,add ax,bx會被執行(類似 ax=ax+bx)。寄存器ax的值已經變成了之前寄存器ax和bx中的數據之和0003;寄存器IP的值增加了2(add ax,bx的指令長度是2),CS:IP指向1000:8。

  

A命令 以彙編指令的形式向記憶體中寫入內容

  A命令能夠以彙編指令的形式向記憶體中寫入內容

  對於記憶體操作,D命令可以查看記憶體中的內容,但如果想查看的是程式指令,顯然U命令更加方便;E命令可以向記憶體中寫入數據,但對於程式指令的寫入,直接操作二進位機器碼的方式過於硬核。為此,debug提供了A命令,我們可以通過A命令以彙編指令的形式向記憶體中寫入內容。

  通過A命令將(mov ax,0001,mov bx,0002,add ax,bx)三條指令寫入記憶體1000:0處:

  

  通過A命令進行指令的寫入,和E命令達到的效果一樣,但使用起來卻更加便捷。A命令能夠自動識別所輸入彙編指令的長度,正確的在記憶體中寫入程式指令。

  debug提供了D、E兩種命令用於對記憶體進行通用的操作(純二進位、十六進位數據的讀、寫)。

  對於程式指令,debug提供了U、A兩種命令以更人性化的方式來讀寫記憶體中的指令內容。

三 總結

  在debug模式下可以模擬8086彙編非常自由的控制CPU和記憶體,這也是彙編語言的強大之處和魅力所在。

貼近硬體底層的編程能夠讓我們編寫出來的程式非常高效,但也存在一些問題:

  1.記憶體中的內容被當做指令還是數據來處理完全取決於如何解釋,編程時稍有不慎就會導致CPU執行一些不應該執行的指令,甚至造成巨大的破壞。

  2.在未來還會介紹如何使用彙編語言來實現高級語言中出現的結構體、數組等概念。這些數據結構完全是程式邏輯上的,記憶體本身可沒有這些功能。因此在使用彙編訪問記憶體中結構化的數據時,一不小心就會出現記憶體訪問越界,錯位等問題。

  3.彙編語言的抽象程度過低,許多在高級語言中很簡單的功能在彙編中也需要很多的代碼來實現(彙編實現的控制台列印hello world可能是常用語言中最繁瑣的了)。

  編程語言的貼近底層與機器高效性如果站在更高的角度上看其實是一把雙刃劍:直接操控底層的機器方便,機器執行效率高的同時,也是危險、開發效率底下的。彙編語言程式員不得不付出巨大的精力來仔細思考、斟酌這些底層機器層面的細節,以避免出現相關bug,大大降低了開發效率。這也是高級語言誕生,並不斷發展的主要原因。

  高級語言大家族中按抽象程度來看,從偏底層的C,C++到java、python等,再到目前抽象程度最高的lisp。隨著抽象程度的提高,離機器底層越遠,執行效率通常也隨之降低。但程式員所需要考慮的機器細節也就越少,能更專註於業務邏輯,進而提高了開發效率。比如在使用C編程時還需要仔細考慮指針錯誤,堆上無用記憶體回收等問題,到了更高級的java、python中,這些問題都交由編譯器、虛擬機解決了,對開發人員也幾乎透明瞭。

  天下沒有免費的午餐,在選擇適合的編程語言開發程式時,需要在機器執行效率和開發效率間做出取捨。但隨著科學技術的發展,電腦硬體會越來越強大,對機器效率的擔憂會越來越少,對程式開發效率的考慮將占據主導地位,越來越多的程式將會傾向於使用抽象程度更高的編程語言進行開發。

  雖然需要使用彙編語言的場合越來越少,但對彙編語言和底層機器硬體有一定的瞭解的話,依然能夠幫助程式員更深刻的理解上層的知識內容、寫出更高效的程式。

  畢竟,人類是無法抽象、封裝到完美無缺的,有時還是你需要跳進下水道,深入底層一探究竟的。

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 既要低頭趕路,又要抬頭望天,科技是為人服務的,任何技術背後都有更深層次的考量,在本系列的第一篇文章中我們聊了微服務的本質,它是一種可以加速分工、促進合作的新協作機制。知其然,知其所以然,在第二篇文章中我們剖析了微服務為什麼可以加速分工、促進合作,今天我們再接著來聊聊怎樣開啟微服務架構之旅。 ...
  • 二進位 0000 0000 0000 0000 0000 0000 0000 0001 // 2^0 0000 0000 0000 0000 0000 0000 0000 0010 // 2^1 0000 0000 0000 0000 0000 0000 0000 0100 // 2^2 0000 ...
  • 消息中間件 消息的可靠性傳遞 前言 消息中間件的可靠性消息傳遞,是消息中間件領域非常重要的方案落實問題(在這之前的MQ理論,MQ選型是抽象層次更高的問題,這裡不談)。 並且這個問題與日常開發是存在較大的關聯的。可以這麼說,凡是使用了MQ的,機會都要考慮這個問題。當然也有一些原始數據採集,日誌數據收集 ...
  • 一、訪問網路的兩種方法 1.get:利用參數給伺服器傳遞信息;參數為dict,然後parse解碼 2.post:一般向伺服器傳遞參數使用;post是把信息自動加密處理;如果想要使用post信息,需要使用到data參數 3.Content-Type:application/x-www.form-url ...
  • 前面我們在章節“Socket通訊探索(一)”中如何實現一個tcp連接,但是這僅僅是一個最初級的BIO實現,且沒有添加線程池,實際應用中很少採用這種方式,因為不得不考慮當大量的Tcp連接建立的時候,服務端如何安全穩定的運行?為什麼呢? 1、BIO實現方式,是阻塞式的(上一節最後面的實現方式雖然無數據的 ...
  • 引言 問題 現在我們使用通用的應用程式或庫來相互通信。例如,我們經常使用HTTP客戶機從web伺服器檢索信息,並通過web服務調用遠程過程調用。然而,通用協議或其實現有時不能很好地進行擴展。這就像我們不使用通用HTTP伺服器來交換巨大的文件、電子郵件消息和近乎實時的消息(如財務信息和多人游戲數據)一 ...
  • 一、什麼是socket? 當兩台電腦需要通信的時候,往往我們使用的都是TCP去實現的,但是並不會直接去操作TCP協議,通常是通過Socket進行tcp通信。Socket是操作系統提供給開發者的一個介面,通過它,就可以實現設備之間的通信。 二、TCP是如何通信的? TCP連接和斷開分別會存在3次握手 ...
  • 自JDK1.5引入註解後,他就成為了Java編程語言重要的組成部分,在開發過程中,我們也時常用到@Override、@ToString等這樣的註解。在這篇文章中,將介紹什麼是註解、為什麼引用註解、它是如何工作的、如何編寫自定義註解、以及如何測試自定義註解。 一、什麼是註解? 用一個詞就可以描述註解, ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...