8086匯編開(kāi)發(fā)環(huán)境搭建和Debug模式介紹(圖文詳解)
1. 8086匯編開(kāi)發(fā)環(huán)境搭建
在上篇博客中簡(jiǎn)單的介紹了8086匯編語(yǔ)言。工欲善其事,必先利其器,在8086匯編語(yǔ)言正式開(kāi)始學(xué)習(xí)之前,先介紹一下如何搭建8086匯編的開(kāi)發(fā)環(huán)境。
匯編語(yǔ)言設(shè)計(jì)之初是用于在沒(méi)有操作系統(tǒng)的裸機(jī)上直接操作硬件的,但對(duì)于大部分人來(lái)說(shuō),在8086裸機(jī)上直接進(jìn)行編程將會(huì)面臨各種困難。好在我們可以使用軟件模擬器來(lái)模擬硬件進(jìn)行8086的學(xué)習(xí)實(shí)踐。在《匯編語(yǔ)言》中作者推薦通過(guò)windows環(huán)境下的masm和debug進(jìn)行學(xué)習(xí)。
masm介紹:
masm是一款DOS下的匯編工具包,在8086匯編的學(xué)習(xí)中我們需要其中的幾個(gè)文件,分別是masm.exe,link.exe。
masm.exe匯編器,用于將文本格式的匯編語(yǔ)言源文件編譯為.obj結(jié)尾的二進(jìn)制文件,其生成的.obj結(jié)尾的二進(jìn)制目標(biāo)文件是被編譯的源文件的對(duì)應(yīng)的機(jī)器碼。單獨(dú)的源程序目標(biāo)文件通常是無(wú)法直接運(yùn)行的,還需要和互相依賴(lài)的其它同樣編譯完成的二進(jìn)制文件鏈接在一起才能生成最終的可執(zhí)行文件(比如所需要的靜態(tài)庫(kù)函數(shù))。因此,obj文件通常也被叫做中間文件。
link.exe鏈接器,obj文件需要通過(guò)鏈接才能轉(zhuǎn)換成可執(zhí)行程序,而鏈接器就是負(fù)責(zé)完成這一任務(wù)的。鏈接器能將多個(gè)obj目標(biāo)文件以及其所依賴(lài)的庫(kù)程序進(jìn)行統(tǒng)一處理(例如多個(gè)目標(biāo)文件中指令、數(shù)據(jù)內(nèi)存地址的偏移處理),并生成可執(zhí)行文件。
debug介紹:
debug.exe調(diào)試器,windows提供了一個(gè)在dos中調(diào)試8086匯編程序的工具debug.exe,提供了展示程序運(yùn)行時(shí)CPU中各寄存器、內(nèi)存中數(shù)據(jù),指令級(jí)的單步調(diào)試等功能。debug程序的使用會(huì)在本篇博客的后半段進(jìn)行詳細(xì)介紹。
64位操作系統(tǒng)兼容性問(wèn)題:
由于《匯編語(yǔ)言》一書(shū)出版較早,當(dāng)時(shí)的windows系統(tǒng)還是32位的,32位windows系統(tǒng)都默認(rèn)安裝了masm與debug,能打開(kāi)dos窗口直接使用。但目前普遍使用的、新的windows 64位操作系統(tǒng)中卻并沒(méi)有默認(rèn)提供masm工具包和debug.exe,同時(shí)masm、debug也與64位的windows系統(tǒng)版本不兼容。
想在64位的windows系統(tǒng)下使用masm、debug有兩個(gè)常用方法:
1. 通過(guò)虛擬機(jī)安裝一個(gè)老版本的windows操作系統(tǒng)(推薦windows xp)
2. 通過(guò)DOSBox這一輕量級(jí)的ms-dos模擬器來(lái)運(yùn)行,但上文所述的依賴(lài)程序需單獨(dú)下載(百度網(wǎng)盤(pán)下載鏈接:
鏈接: https://pan.baidu.com/s/1JlOEFoV7h37Z_NY7NKc-gw
提取碼: x3ai
個(gè)人推薦第二種方法,下面介紹如何在windows64位操作系統(tǒng)下使用DOSBox來(lái)搭建8086匯編語(yǔ)言的開(kāi)發(fā)環(huán)境。
DOSBox安裝與使用
DOSBox下載安裝:
DOSBox可以在官網(wǎng)下載,這里也提供了百度網(wǎng)盤(pán)的下載鏈接(0.74版本):
鏈接: https://pan.baidu.com/s/1W3f6_jsSK4HrHWDO_IfqRg
提取碼: 7ugx
安裝完畢后,找到安裝目錄下的DOSBox.exe并啟動(dòng),能看到如下圖界面。
作為dos的模擬器和普通的dos窗口沒(méi)有明顯區(qū)別,但是初始時(shí)并不能直接訪問(wèn)到本地磁盤(pán),需要先將本地磁盤(pán)掛載到DOSBox中。
DOSBox掛載本地磁盤(pán):
1. 在本地操作系統(tǒng)磁盤(pán)上選擇一個(gè)文件夾目錄,作為掛載的磁盤(pán)路徑(例如C:\dos)
2. 在DOSBox啟動(dòng)的dos窗口中執(zhí)行命令:mount C C:\dos(代表著將本地的C:\dos路徑掛載到DOSBox的C盤(pán)路徑下),能把dos窗口的工作目錄切換到C盤(pán),接下來(lái)就可以正常訪問(wèn)被掛載的磁盤(pán)路徑下的內(nèi)容了。
3. 將前面提到過(guò)的debug.exe等文件都放在這個(gè)掛載的本地磁盤(pán)路徑下(例如C:\dos),通過(guò)DOSBox就可以兼容的運(yùn)行masm工具包中的程序和debug.exe了
添加自動(dòng)執(zhí)行腳本以避免重復(fù)操作:
由于上述DOSBox的磁盤(pán)掛載是臨時(shí)的,每次重新啟動(dòng)DOSBox后都需要重新輸入命令進(jìn)行掛載,太麻煩了。我們可以通過(guò)修改DOSBox配置的方式,免去這些重復(fù)的操作。
找到DOSBox安裝目錄下的DOSBox 0.74 Options.bat,使用系統(tǒng)自帶的記事本直接打開(kāi),暫不研究其它配置段的作用,找到最后的【autoexec】段,配置在【autoexec】的內(nèi)容會(huì)作為命令在DOSBox啟動(dòng)時(shí)按順序被自動(dòng)執(zhí)行?! ?/p>
將掛載磁盤(pán)操作命令配置在【autoexec】段中能避免重復(fù)操作。修改并保存配置文件后,重新啟動(dòng)DOSBox,發(fā)現(xiàn)配置中添加的命令會(huì)被自動(dòng)執(zhí)行。
2. 8086debug模式介紹
在搭建好了8086匯編的開(kāi)發(fā)環(huán)境后,接下來(lái)介紹8086的debug模式。執(zhí)行debug.exe以進(jìn)入debug調(diào)試模式,在dos中通過(guò)輸入命令的方式進(jìn)行交互。
debug模式下有20多種不同命令,限于篇幅這里只會(huì)介紹幾個(gè)以后實(shí)驗(yàn)時(shí)常用到的命令。(通過(guò)回車(chē)執(zhí)行命令,DOS下的命令默認(rèn)是不區(qū)分大小寫(xiě)的)
R命令查看/改變CPU寄存器內(nèi)容
R命令的作用是查看和修改debug模式下CPU中寄存器的值。
(-r)單獨(dú)的輸入r,可以查看當(dāng)前CPU的內(nèi)容
(-r 寄存器名) r加上寄存器名可以在接下來(lái)的":"提示后輸入新的值,以達(dá)到修改對(duì)應(yīng)寄存器內(nèi)容的目的(示例中第二行 AX 0000表示修改前寄存器AX的值為0000)
D命令 查看內(nèi)存中的內(nèi)容
D命令的作用是查看內(nèi)存中的內(nèi)容。
D命令有許多不同的傳參方式可供使用,先介紹最易理解的(段地址:偏移地址)查看方式。D命令默認(rèn)會(huì)顯示尋址地址開(kāi)始的后128個(gè)內(nèi)存單元的內(nèi)容,以16進(jìn)制的方式顯示(每個(gè)內(nèi)存單元8位,一行最多16個(gè)內(nèi)存單元),而最右邊會(huì)將內(nèi)存單元中的二進(jìn)制數(shù)據(jù)以ascll碼的形式翻譯展示。
有時(shí),我們只想聚焦于某一部分內(nèi)存地址的內(nèi)容,而默認(rèn)展示的內(nèi)存視圖不是很方便。
D命令提供了另外一種訪問(wèn)內(nèi)存的方式(段地址:偏移起始地址 偏移終止地址),其能夠展示(段地址:偏移起始地址 至 段地址:偏移終止地址)的內(nèi)存信息,范圍兩端均為閉區(qū)間。
E命令 改變內(nèi)存中的內(nèi)容
E命令的作用是改變內(nèi)存中的內(nèi)容。
和對(duì)CPU中寄存器的查看,修改不同,對(duì)內(nèi)存進(jìn)行查看和修改較為復(fù)雜,為此debug設(shè)計(jì)了兩個(gè)不同的命令分別進(jìn)行控制(E命令修改內(nèi)存、D命令查看內(nèi)存)。
通過(guò)(E 起始地址 數(shù)據(jù)1 數(shù)據(jù)2 數(shù)據(jù)3...)命令可以修改內(nèi)存中以起始地址開(kāi)始,順序的N個(gè)內(nèi)存單元的值(N為實(shí)際參數(shù)傳遞的數(shù)量)。
也可以和R命令修改CPU中寄存器值類(lèi)似的,通過(guò)提示來(lái)修改特定內(nèi)存單元的值。00.12 00代表內(nèi)存單元在修改前的值,12是我們手動(dòng)輸入的、需要修改的新值。
可以通過(guò)E命令向內(nèi)存輸入對(duì)應(yīng)的機(jī)器指令,因?yàn)闄C(jī)器指令也是數(shù)據(jù)的一種。
有以下指令(左側(cè)為機(jī)器碼,右側(cè)為對(duì)應(yīng)的匯編指令):
B80100 mov ax,0001
BB0200 mov bx,0002
01D8 add ax,bx
我們可以向內(nèi)存1000:0處寫(xiě)入這些機(jī)器指令,以供接下來(lái)通過(guò)debug執(zhí)行這段機(jī)器指令 (執(zhí)行命令:E 1000:0 B8 01 00 BB 02 00 01 D8)。
U命令 將內(nèi)存數(shù)據(jù)轉(zhuǎn)換為匯編指令展示
U命令的作用是將內(nèi)存中的二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為匯編指令展示(反匯編)。
D命令能夠?qū)?nèi)存中的數(shù)據(jù)以16進(jìn)制或ascll碼的形式展現(xiàn)出來(lái),但有時(shí)我們需要觀察的是內(nèi)存中的機(jī)器指令時(shí),D命令的視圖過(guò)于抽象,不利于理解。debug提供了U命令來(lái)解決這個(gè)問(wèn)題。
對(duì)于前面我們?cè)?000:0處輸入的機(jī)器指令,使用 U 1000:0 命令(u 內(nèi)存地址)可以將內(nèi)存中的數(shù)據(jù)以匯編語(yǔ)言指令的方式進(jìn)行展示。
可以觀察到,左邊展示的是內(nèi)存地址,中間則是16進(jìn)制的內(nèi)存視圖,右邊展示的是內(nèi)存中數(shù)據(jù)所對(duì)應(yīng)的匯編指令(例如:1000:0000;B80100;MOV AX,0001)。
由于我們只輸入了三條匯編指令,而后面內(nèi)存中的數(shù)據(jù)并不是我們想要執(zhí)行的,但U命令卻依然將其以匯編指令的形式轉(zhuǎn)換并顯示出來(lái)了。
這也是前一篇博客所提到的,內(nèi)存中的數(shù)據(jù)完全是二進(jìn)制的,既可以將其看做普通的二進(jìn)制數(shù)據(jù)、十六進(jìn)制數(shù)據(jù)、ascll碼文本數(shù)據(jù),也可以視作程序指令,這些二進(jìn)制的"數(shù)據(jù)"的處理完全取決于如何對(duì)其進(jìn)行解釋。
T命令 單步執(zhí)行機(jī)器指令
T命令的作用是進(jìn)行單步機(jī)器指令的調(diào)試
以上文通過(guò)E命令寫(xiě)入內(nèi)存1000:0的三條指令舉例,介紹如何使用T命令來(lái)讓CPU執(zhí)行1000:0處的機(jī)器指令。T命令用于單步調(diào)試,一次只會(huì)執(zhí)行一條機(jī)器指令。
8086CPU在運(yùn)行時(shí)會(huì)將CS:IP寄存器所指向的內(nèi)存單元中的內(nèi)容解釋為指令執(zhí)行,要將內(nèi)存1000:0處的內(nèi)容作為指令執(zhí)行必須先修改CS、IP兩個(gè)寄存器的值,使之指向1000:0。
先執(zhí)行一次T命令,1000:0處的指令(mov ax,0001)便會(huì)被執(zhí)行,可以觀察到寄存器ax的值已經(jīng)變成了0001;同時(shí)寄存器IP的值增加了3(mov ax,0001的指令長(zhǎng)度為3),此時(shí)CS:IP指向的便是位于1000:3處的下一條指令(mov bx,0002),在視圖的最后一行中也有所體現(xiàn)。
再執(zhí)行一次T命令,會(huì)執(zhí)行1000:3處的指令(mov bx,0002),可以觀察到寄存器bx的值變成了0002;寄存器IP的值又增加了3(mov bx,0002的指令長(zhǎng)度也是3),此時(shí)CS:IP指向的便是位于1000:6處的下一條指令(add ax,bx)。
最后執(zhí)行一次T命令,add ax,bx會(huì)被執(zhí)行(類(lèi)似 ax=ax+bx)。寄存器ax的值已經(jīng)變成了之前寄存器ax和bx中的數(shù)據(jù)之和0003;寄存器IP的值增加了2(add ax,bx的指令長(zhǎng)度是2),CS:IP指向1000:8。
A命令 以匯編指令的形式向內(nèi)存中寫(xiě)入內(nèi)容
A命令能夠以匯編指令的形式向內(nèi)存中寫(xiě)入內(nèi)容
對(duì)于內(nèi)存操作,D命令可以查看內(nèi)存中的內(nèi)容,但如果想查看的是程序指令,顯然U命令更加方便;E命令可以向內(nèi)存中寫(xiě)入數(shù)據(jù),但對(duì)于程序指令的寫(xiě)入,直接操作二進(jìn)制機(jī)器碼的方式過(guò)于硬核。為此,debug提供了A命令,我們可以通過(guò)A命令以匯編指令的形式向內(nèi)存中寫(xiě)入內(nèi)容。
通過(guò)A命令將(mov ax,0001,mov bx,0002,add ax,bx)三條指令寫(xiě)入內(nèi)存1000:0處:
通過(guò)A命令進(jìn)行指令的寫(xiě)入,和E命令達(dá)到的效果一樣,但使用起來(lái)卻更加便捷。A命令能夠自動(dòng)識(shí)別所輸入?yún)R編指令的長(zhǎng)度,正確的在內(nèi)存中寫(xiě)入程序指令。
debug提供了D、E兩種命令用于對(duì)內(nèi)存進(jìn)行通用的操作(純二進(jìn)制、十六進(jìn)制數(shù)據(jù)的讀、寫(xiě))。
對(duì)于程序指令,debug提供了U、A兩種命令以更人性化的方式來(lái)讀寫(xiě)內(nèi)存中的指令內(nèi)容。
三 總結(jié)
在debug模式下可以模擬8086匯編非常自由的控制CPU和內(nèi)存,這也是匯編語(yǔ)言的強(qiáng)大之處和魅力所在。
貼近硬件底層的編程能夠讓我們編寫(xiě)出來(lái)的程序非常高效,但也存在一些問(wèn)題:
1.內(nèi)存中的內(nèi)容被當(dāng)做指令還是數(shù)據(jù)來(lái)處理完全取決于如何解釋?zhuān)幊虝r(shí)稍有不慎就會(huì)導(dǎo)致CPU執(zhí)行一些不應(yīng)該執(zhí)行的指令,甚至造成巨大的破壞。
2.在未來(lái)還會(huì)介紹如何使用匯編語(yǔ)言來(lái)實(shí)現(xiàn)高級(jí)語(yǔ)言中出現(xiàn)的結(jié)構(gòu)體、數(shù)組等概念。這些數(shù)據(jù)結(jié)構(gòu)完全是程序邏輯上的,內(nèi)存本身可沒(méi)有這些功能。因此在使用匯編訪問(wèn)內(nèi)存中結(jié)構(gòu)化的數(shù)據(jù)時(shí),一不小心就會(huì)出現(xiàn)內(nèi)存訪問(wèn)越界,錯(cuò)位等問(wèn)題。
3.匯編語(yǔ)言的抽象程度過(guò)低,許多在高級(jí)語(yǔ)言中很簡(jiǎn)單的功能在匯編中也需要很多的代碼來(lái)實(shí)現(xiàn)(匯編實(shí)現(xiàn)的控制臺(tái)打印helloworld可能是常用語(yǔ)言中最繁瑣的了)。
編程語(yǔ)言的貼近底層與機(jī)器高效性如果站在更高的角度上看其實(shí)是一把雙刃劍:直接操控底層的機(jī)器方便,機(jī)器執(zhí)行效率高的同時(shí),也是危險(xiǎn)、開(kāi)發(fā)效率底下的。匯編語(yǔ)言程序員不得不付出巨大的精力來(lái)仔細(xì)思考、斟酌這些底層機(jī)器層面的細(xì)節(jié),以避免出現(xiàn)相關(guān)bug,大大降低了開(kāi)發(fā)效率。這也是高級(jí)語(yǔ)言誕生,并不斷發(fā)展的主要原因。
高級(jí)語(yǔ)言大家族中按抽象程度來(lái)看,從偏底層的C,C++到j(luò)ava、python等,再到目前抽象程度最高的lisp。隨著抽象程度的提高,離機(jī)器底層越遠(yuǎn),執(zhí)行效率通常也隨之降低。但程序員所需要考慮的機(jī)器細(xì)節(jié)也就越少,能更專(zhuān)注于業(yè)務(wù)邏輯,進(jìn)而提高了開(kāi)發(fā)效率。比如在使用C編程時(shí)還需要仔細(xì)考慮指針錯(cuò)誤,堆上無(wú)用內(nèi)存回收等問(wèn)題,到了更高級(jí)的java、python中,這些問(wèn)題都交由編譯器、虛擬機(jī)解決了,對(duì)開(kāi)發(fā)人員也幾乎透明了。
天下沒(méi)有免費(fèi)的午餐,在選擇適合的編程語(yǔ)言開(kāi)發(fā)程序時(shí),需要在機(jī)器執(zhí)行效率和開(kāi)發(fā)效率間做出取舍。但隨著科學(xué)技術(shù)的發(fā)展,計(jì)算機(jī)硬件會(huì)越來(lái)越強(qiáng)大,對(duì)機(jī)器效率的擔(dān)憂會(huì)越來(lái)越少,對(duì)程序開(kāi)發(fā)效率的考慮將占據(jù)主導(dǎo)地位,越來(lái)越多的程序?qū)?huì)傾向于使用抽象程度更高的編程語(yǔ)言進(jìn)行開(kāi)發(fā)。
雖然需要使用匯編語(yǔ)言的場(chǎng)合越來(lái)越少,但對(duì)匯編語(yǔ)言和底層機(jī)器硬件有一定的了解的話,依然能夠幫助程序員更深刻的理解上層的知識(shí)內(nèi)容、寫(xiě)出更高效的程序。
畢竟,人類(lèi)是無(wú)法抽象、封裝到完美無(wú)缺的,有時(shí)還是你需要跳進(jìn)下水道,深入底層一探究竟的。
總結(jié)
以上所述是小編給大家介紹的8086匯編開(kāi)發(fā)環(huán)境搭建和Debug模式介紹,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
ARM匯編解決階乘及大小寫(xiě)轉(zhuǎn)換的問(wèn)題
這篇文章主要介紹了ARM匯編解決階乘及大小寫(xiě)轉(zhuǎn)換,包括ARM匯編大小寫(xiě)轉(zhuǎn)換以及存入內(nèi)存的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-11-11匯編語(yǔ)言 and和or邏輯運(yùn)算指令的實(shí)現(xiàn)
這篇文章主要介紹了匯編語(yǔ)言 and,or邏輯運(yùn)算指令的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01匯編語(yǔ)言MUL指令無(wú)符號(hào)數(shù)乘法的使用
這篇文章主要介紹了匯編語(yǔ)言MUL指令無(wú)符號(hào)數(shù)乘法的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02計(jì)算機(jī)系統(tǒng)匯編語(yǔ)言和機(jī)器語(yǔ)言深入理解
這篇文章主要為大家介紹了計(jì)算機(jī)系統(tǒng)匯編語(yǔ)言和機(jī)器語(yǔ)言深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09詳解如何在Mac上用匯編語(yǔ)言寫(xiě)HelloWorld
這篇文章主要介紹了詳解如何在Mac上用匯編語(yǔ)言寫(xiě)HelloWorld,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01淺析ELF轉(zhuǎn)二進(jìn)制允許把 Binary 文件加載到任意位置
本文通過(guò) eip + 偏移地址 實(shí)現(xiàn)了運(yùn)行時(shí)計(jì)算數(shù)據(jù)地址,不再需要把 Binary 文件裝載到固定的位置。本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2020-02-02匯編語(yǔ)言系列之匯編實(shí)現(xiàn)字符串操作
本文列出了字符串匹配和字符串輸入顯示的代碼,對(duì)匯編語(yǔ)言系列之匯編實(shí)現(xiàn)字符串操作相關(guān)知識(shí)感興趣的朋友跟隨小編一起看看吧2021-11-11