匯編語言手冊.docx_第1頁
匯編語言手冊.docx_第2頁
匯編語言手冊.docx_第3頁
匯編語言手冊.docx_第4頁
匯編語言手冊.docx_第5頁
免費預(yù)覽已結(jié)束,剩余7頁可下載查看

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

寄存器與存儲器1. 寄存器功能. 寄存器的一般用途和專用用途. CS:IP 控制程序執(zhí)行流程. SS:SP 提供堆棧棧頂單元地址. DS:BX(SI,DI) 提供數(shù)據(jù)段內(nèi)單元地址. SS:BP 提供堆棧內(nèi)單元地址. ES:BX(SI,DI) 提供附加段內(nèi)單元地址. AX,CX,BX和CX寄存器多用于運算和暫存中間計算結(jié)果,但又專用于某些指令(查閱 指令表)。. PSW程序狀態(tài)字寄存器只能通過專用指令(LAHF, SAHF)和堆棧(PUSHF,POPF)進(jìn)行存取。2. 存儲器分段管理. 解決了16位寄存器構(gòu)成20位地址的問題. 便于程序重定位. 20位物理地址=段地址 * 16 + 偏移地址. 程序分段組織: 一般由代碼段,堆棧段,數(shù)據(jù)段和附加段組成,不設(shè)置堆棧段時 則使用系統(tǒng)內(nèi)部的堆棧。3. 堆棧. 堆棧是一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu) , 數(shù)據(jù)的存取在棧頂進(jìn)行 , 數(shù)據(jù)入棧使堆棧向地址減小的方向擴展。. 堆棧常用于保存子程序調(diào)用和中斷響應(yīng)時的斷點以及暫存數(shù)據(jù)或中間計算結(jié)果 。 .堆??偸且宰譃閱挝淮嫒≈噶钕到y(tǒng)與尋址方式1. 指令系統(tǒng). 計算機提供給用戶使用的機器指令集稱為指令系統(tǒng),大多數(shù)指令為雙操作數(shù)指令。執(zhí)行指令后,一般源操作數(shù)不變,目的操作數(shù)被計算結(jié)果替代。. 機器指令由CPU執(zhí)行,完成某種運算或操作,8086/8088指令系統(tǒng)中的指令分為6類: 數(shù)據(jù)傳送,算術(shù)運算,邏輯運算,串操作,控制轉(zhuǎn)移和處理機控制。2. 尋址方式. 尋址方式確定執(zhí)行指令時獲得操作數(shù)地址的方法. 分為與數(shù)據(jù)有關(guān)的尋址方式(7種)和與轉(zhuǎn)移地址有關(guān)的尋址方式(4)種。. 與數(shù)據(jù)有關(guān)的尋址方式的一般用途:(1) 立即數(shù)尋址方式-將常量賦給寄存器或存儲單元(2) 直接尋址方式-存取單個變量(3) 寄存器尋址方式-訪問寄存器的速度快于訪問存儲單元的速度(4) 寄存器間接尋址方式-訪問數(shù)組元素(5) 變址尋址方式(6) 基址變址尋址方式(7) 相對基址變址尋址方式 (5),(6),(7)都便于處理數(shù)組元素. 與數(shù)據(jù)有關(guān)的尋址方式中,提供地址的寄存器只能是BX,SI,DI或BP. 與轉(zhuǎn)移地址有關(guān)的尋址方式的一般用途:(1) 段內(nèi)直接尋址-段內(nèi)直接轉(zhuǎn)移或子程序調(diào)用(2) 段內(nèi)間接尋址-段內(nèi)間接轉(zhuǎn)移或子程序調(diào)用(3) 段間直接尋址-段間直接轉(zhuǎn)移或子程序調(diào)用(4) 段間間接尋址-段間間接轉(zhuǎn)移或子程序調(diào)用匯編程序和匯編語言1. 匯編程序. 匯編程序是將匯編語言源程序翻譯成二進(jìn)制代碼程序的語言處理程序,翻譯的過程稱為匯編。2. 匯編語言. 匯編語言是用指令助記符,各種標(biāo)識變量,地址,過程等的標(biāo)識符書寫程序的語言, 匯編語言指令與機器指令一 一對應(yīng)。. 偽指令,宏指令不是由CPU執(zhí)行的指令,而是由匯編程序在匯編期間處理的指令。. 偽指令指示匯編程序如何完成數(shù)據(jù)定義,存儲空間分配,組織段等工作。. 宏指令可簡化程序并減少程序書寫量。. 條件匯編偽指令的功能是確定是否匯編某段源程序,而不是實現(xiàn)程序分支,對未匯編的程序?qū)⒉划a(chǎn)生相應(yīng)的目標(biāo)代碼。. 結(jié)構(gòu)作為一種數(shù)據(jù)結(jié)構(gòu)可將一組類型不同但有邏輯關(guān)聯(lián)的數(shù)據(jù)組織在一起,便于 整體處理數(shù)據(jù)。. 記錄可用于提高存儲單元的利用率,將若干不足一個字節(jié)或字且有邏輯關(guān)聯(lián)的信 息壓縮存放在一個字節(jié)或字中。. 指令中的表達(dá)式在匯編期間計算,并且只能對常量或地址進(jìn)行計算。程序設(shè)計基礎(chǔ)1. 分支程序設(shè)計. 程序分支由條件轉(zhuǎn)移指令或無條件轉(zhuǎn)移指令實現(xiàn). 存放若干目的轉(zhuǎn)移地址或跳轉(zhuǎn)指令的跳轉(zhuǎn)表常用于實現(xiàn)多路分支. 條件轉(zhuǎn)移指令只能實現(xiàn)偏移量為-128至+127字節(jié)范圍的轉(zhuǎn)移. 無條件轉(zhuǎn)移指令根據(jù)尋址方式可實現(xiàn)短轉(zhuǎn)移(偏移量為-128至+127字節(jié)),段內(nèi)轉(zhuǎn) 移,段間轉(zhuǎn)移。2. 循環(huán)程序設(shè)計. 可由循環(huán)控制指令或條件轉(zhuǎn)移指令組織循環(huán)結(jié)構(gòu). 內(nèi)層循環(huán)結(jié)構(gòu)必須完全包含在外層循環(huán)結(jié)構(gòu)內(nèi),并不能發(fā)生從循環(huán)結(jié)構(gòu)外向循環(huán) 結(jié)構(gòu)內(nèi)的轉(zhuǎn)移。3. 子程序設(shè)計. 子程序中應(yīng)保護(hù)寄存器內(nèi)容,并正確使用堆棧, 成對執(zhí)行PUSH和POP指令,保證執(zhí)行RET指令時堆棧棧頂為返回地址。. 主程序可通過寄存器,參數(shù)表,或堆棧傳遞參數(shù)給子程序 4. EXE文件和COM文件. 二者都是可執(zhí)行文件. COM文件源程序的特點是: 第一條可執(zhí)行指令的起始存放地址必須是100H,不能分段,不用定義堆棧,所有過程為NEAR類型,直接用INT 20H 指令返回DOS。5. DOS功能調(diào)用與BIOS中斷調(diào)用. 二者都是完成DOS系統(tǒng)提供給用戶的輸入/輸出等常用功能,通過執(zhí)行軟中斷指令 完成一次軟中斷服務(wù)。. DOS功能調(diào)用的中斷服務(wù)程序是操作系統(tǒng)的一部分,存于RAM中; 而BIOS中斷調(diào)用的中斷服務(wù)程序存放在ROM中。輸入/輸出與中斷系統(tǒng)1. 輸入/輸出的方式. 程序直接I/O方式: 用IN和OUT指令直接在端口級上進(jìn)行I/O操作,數(shù)據(jù)傳送方式 分為無條件傳送方式和查詢傳送方式。. 中斷傳送方式: 由CPU響應(yīng)中斷請求完成中斷服務(wù)。. DMA傳送方式: 直接在存儲器與外設(shè)之間傳送數(shù)據(jù)。2. 有關(guān)中斷的概念. 中斷、中斷源、中斷請求、中斷服務(wù)、中斷向量、中斷向量表、中斷響應(yīng)過程、中斷指令、開中斷、關(guān)中斷、內(nèi)部中斷、外部中斷、可屏蔽中斷、非屏蔽中斷。3. 鍵盤I/O、顯示器I/O操作. 鍵盤的輸入操作用BIOS的16H中斷調(diào)用控制,也可直接訪問60H端口(數(shù)據(jù)端口), 61H端口(狀態(tài)端口)檢測鍵盤的按鍵操作。. 對于特殊鍵(如Shift , Ctrl , Alt , NumLock , ScrollLock等鍵)的按動情況,可以直接從來40:17H單元取得有關(guān)信息。. 顯示器的圖形顯示可以用BIOS的10H中斷調(diào)用實現(xiàn),另一種速度更快的方法是直 接讀寫視頻緩沖區(qū)。4. 打印機I/O操作由 INT 17H中斷調(diào)用實現(xiàn), 串行通訊口操作由 INT 14H中斷調(diào)用實現(xiàn)。CLD Clear the direction flag (set to forward direction)將方向標(biāo)志置0,使si和di增量,串處理從低地址向高地址處理8088 匯編速查手冊一、數(shù)據(jù)傳輸指令它們在存貯器和寄存器、寄存器和輸入輸出端口之間傳送數(shù)據(jù).1. 通用數(shù)據(jù)傳送指令.MOV傳送字或字節(jié).MOVSX先符號擴展,再傳送.MOVZX先零擴展,再傳送.PUSH把字壓入堆棧.POP把字彈出堆棧.PUSHA把AX,CX,DX,BX,SP,BP,SI,DI依次壓入堆棧.POPA把DI,SI,BP,SP,BX,DX,CX,AX依次彈出堆棧.PUSHAD把EAX,ECX,EDX, EBX,ESP,EBP,ESI,EDI依次壓入堆棧.POPAD把EDI,ESI,EBP,ESP,EBX,EDX, ECX,EAX依次彈出堆棧.BSWAP交換32位寄存器里字節(jié)的順序XCHG交換字或字節(jié).( 至少有一個操作數(shù)為寄存器,段寄存器不可作為操作數(shù))CMPXCHG 比較并交換操作數(shù).( 第二個操作數(shù)必須為累加器AL/AX/EAX )XADD先交換再累加.( 結(jié)果在第一個操作數(shù)里 )XLAT字節(jié)查表轉(zhuǎn)換. BX 指向一張 256 字節(jié)的表的起點, AL 為表的索引值 (0-255,即0-FFH); 返回 AL 為查表結(jié)果. ( BX+AL-AL )2. 輸入輸出端口傳送指令.INI/O端口輸入. ( 語法: IN 累加器, 端口號DX )OUTI/O端口輸出. ( 語法: OUT 端口號DX,累加器 )輸入輸出端口由立即方式指定時, 其范圍是 0-255; 由寄存器 DX 指定時,其范圍是 0-65535.3. 目的地址傳送指令.LEA裝入有效地址. 例: LEA DX,string;把偏移地址存到DX.LDS傳送目標(biāo)指針,把指針內(nèi)容裝入DS.例: LDS SI,string;把段地址:偏移地址存到DS:SI.LES傳送目標(biāo)指針,把指針內(nèi)容裝入ES.例: LES DI,string;把段地址:偏移地址存到ES:DI.LFS傳送目標(biāo)指針,把指針內(nèi)容裝入FS.例: LFS DI,string;把段地址:偏移地址存到FS:DI.LGS傳送目標(biāo)指針,把指針內(nèi)容裝入GS.例: LGS DI,string;把段地址:偏移地址存到GS:DI.LSS傳送目標(biāo)指針,把指針內(nèi)容裝入SS.例: LSS DI,string;把段地址:偏移地址存到SS:DI.4. 標(biāo)志傳送指令.LAHF標(biāo)志寄存器傳送,把標(biāo)志裝入AH.SAHF標(biāo)志寄存器傳送,把 AH內(nèi)容裝入標(biāo)志寄存器.PUSHF標(biāo)志入棧.POPF標(biāo)志出棧.PUSHD32位標(biāo)志入棧.POPD32位標(biāo)志出棧.二、算術(shù)運算指令A(yù)DD 加法.ADC帶進(jìn)位加法.INC加 1.AAA加法的ASCII碼調(diào)整.DAA加法的十進(jìn)制調(diào)整.SUB減法.SBB帶借位減法.DEC減 1.NEC求反(以 0 減之).CMP比較.(兩操作數(shù)作減法,僅修改標(biāo)志位,不回送結(jié)果).AAS減法的 ASCII碼調(diào)整.DAS減法的十進(jìn)制調(diào)整.MUL無符號乘法.IMUL整數(shù)乘法.以上兩條,結(jié)果回送AH和AL(字節(jié)運算),或DX和AX(字運算),AAM乘法的ASCII碼調(diào)整.DIV無符號除法.IDIV整數(shù)除法.以上兩條,結(jié)果回送:商回送AL,余數(shù)回送AH, (字節(jié)運算);或商回送AX,余數(shù)回送DX, (字運算).AAD除法的ASCII碼調(diào)整.CBW字節(jié)轉(zhuǎn)換為字. (把AL中字節(jié)的符號擴展到AH中去)CWD字轉(zhuǎn)換為雙字. (把AX中的字的符號擴展到DX中去)CWDE字轉(zhuǎn)換為雙字. (把AX中的字符號擴展到EAX中去)CDQ雙字?jǐn)U展.(把EAX中的字的符號擴展到EDX中去)三、邏輯運算指令A(yù)ND與運算.OR或運算.XOR異或運算.NOT取反.TEST測試.(兩操作數(shù)作與運算,僅修改標(biāo)志位,不回送結(jié)果).SHL邏輯左移.SAL算術(shù)左移.(=SHL)SHR邏輯右移.SAR算術(shù)右移.(=SHR)ROL循環(huán)左移.ROR循環(huán)右移.RCL通過進(jìn)位的循環(huán)左移.RCR通過進(jìn)位的循環(huán)右移.以上八種移位指令,其移位次數(shù)可達(dá)255次.移位一次時, 可直接用操作碼.如 SHL AX,1.移位1次時, 則由寄存器CL給出移位次數(shù).如MOV CL,04SHL AX,CL四、串指令DS:SI源串段寄存器:源串變址.ES:DI目標(biāo)串段寄存器:目標(biāo)串變址.CX重復(fù)次數(shù)計數(shù)器.AL/AX掃描值.D標(biāo)志0表示重復(fù)操作中SI和DI應(yīng)自動增量; 1表示應(yīng)自動減量.Z標(biāo)志用來控制掃描或比較操作的結(jié)束.MOVS串傳送.( MOVSB傳送字符.MOVSW傳送字.MOVSD傳送雙字. )CMPS串比較.( CMPSB比較字符.CMPSW比較字. )SCAS串掃描.把AL或AX的內(nèi)容與目標(biāo)串作比較,比較結(jié)果反映在標(biāo)志位.LODS裝入串.把源串中的元素(字或字節(jié))逐一裝入AL或AX中.( LODSB傳送字符.LODSW傳送字.LODSD傳送雙字. )STOS保存串. 是LODS的逆過程.REP當(dāng)CX/ECX0時重復(fù).REPE/REPZ當(dāng)ZF=1或比較結(jié)果相等,且 CX/ECX0時重復(fù).REPNE/REPNZ當(dāng)ZF=0或比較結(jié)果不相等,且 CX/ECX0時重復(fù).REPC當(dāng)CF=1且CX/ECX0時重復(fù).REPNC當(dāng)CF=0且CX/ECX0時重復(fù).五、程序轉(zhuǎn)移指令1無條件轉(zhuǎn)移指令 (長轉(zhuǎn)移)JMP無條件轉(zhuǎn)移指令CALL過程調(diào)用 RET/RETF過程返回.2條件轉(zhuǎn)移指令 (短轉(zhuǎn)移,-128到+127的距離內(nèi))( 當(dāng)且僅當(dāng)(SF XOR OF)=1時,OP1循環(huán)控制指令(短轉(zhuǎn)移)LOOPCX不為零時循環(huán).LOOPE/LOOPZCX不為零且標(biāo)志Z=1時循環(huán).LOOPNE/LOOPNZCX 不為零且標(biāo)志Z=0時循環(huán).JCXZCX為零時轉(zhuǎn)移.JECXZECX 為零時轉(zhuǎn)移.4中斷指令I(lǐng)NT中斷指令I(lǐng)NTO 溢出中斷IRET中斷返回5處理器控制指令 HLT處理器暫停, 直到出現(xiàn)中斷或復(fù)位信號才繼續(xù).WAIT當(dāng)芯片引線TEST為高電平時使CPU進(jìn)入等待狀態(tài).ESC轉(zhuǎn)換到外處理器.LOCK封鎖總線.NOP空操作.STC置進(jìn)位標(biāo)志位.CLC清進(jìn)位標(biāo)志位.CMC進(jìn)位標(biāo)志取反.STD置方向標(biāo)志位.CLD清方向標(biāo)志位.STI置中斷允許位.CLI清中斷允許位.六、偽指令DW定義字(2字節(jié)).PROC定義過程.ENDP過程結(jié)束.SEGMENT 定義段.ASSUME建立段寄存器尋址.ENDS段結(jié)束. END程序結(jié)束.匯編語言基礎(chǔ)知識匯編語言和CPU以及內(nèi)存,端口等硬件知識是連在一起的. 這也是為什么匯編語言沒有通用性的原因. 下面簡單講講基本知識(針對INTEL x86及其兼容機)=x86匯編語言的指令,其操作對象是CPU上的寄存器,系統(tǒng)內(nèi)存,或者立即數(shù). 有些指令表面上沒有操作數(shù), 或者看上去缺少操作數(shù), 其實該指令有內(nèi)定的操作對象, 比如push指令, 一定是對SS:ESP指定的內(nèi)存操作, 而cdq的操作對象一定是eax / edx. 在匯編語言中,寄存器用名字來訪問. CPU 寄存器有好幾類, 分別有不同的用處:1. 通用寄存器:EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP(這個雖然通用,但很少被用做除了堆棧指針外的用途)這些32位可以被用作多種用途,但每一個都有專長. EAX 是累加器(accumulator), 它是很多加法乘法指令的缺省寄存器. EBX 是基地址(base)寄存器, 在內(nèi)存尋址時存放基地址. ECX 是計數(shù)器(counter), 是重復(fù)(REP)前綴指令和LOOP指令的內(nèi)定計數(shù)器. EDX是.(忘了.哈哈)但它總是被用來放整數(shù)除法產(chǎn)生的余數(shù). 這4個寄存器的低16位可以被單獨訪問,分別用AX,BX,CX和DX. AX又可以單獨訪問低8位(AL)和高8位(AH), BX,CX,DX也類似. 函數(shù)的返回值經(jīng)常被放在EAX中.ESI/EDI分別叫做源/目標(biāo)索引寄存器(source/destination index),因為在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目標(biāo)串. EBP是基址指針(BASE POINTER), 它最經(jīng)常被用作高級語言函數(shù)調(diào)用的框架指針(frame pointer). 在破解的時候,經(jīng)??梢钥匆娨粋€標(biāo)準(zhǔn)的函數(shù)起始代碼:push ebp ;保存當(dāng)前ebpmov ebp,esp ;EBP設(shè)為當(dāng)前堆棧指針sub esp, xxx ;預(yù)留xxx字節(jié)給函數(shù)臨時變量.這樣一來,EBP 構(gòu)成了該函數(shù)的一個框架, 在EBP上方分別是原來的EBP, 返回地址和參數(shù). EBP下方則是臨時變量. 函數(shù)返回時作 mov esp,ebp/pop ebp/ret 即可.ESP 專門用作堆棧指針.2. 段寄存器:CS(Code Segment,代碼段) 指定當(dāng)前執(zhí)行的代碼段. EIP (Instruction pointer, 指令指針)則指向該段中一個具體的指令. CS:EIP指向哪個指令, CPU 就執(zhí)行它. 一般只能用jmp, ret, jnz, call 等指令來改變程序流程,而不能直接對它們賦值.DS(DATA SEGMENT, 數(shù)據(jù)段) 指定一個數(shù)據(jù)段. 注意:在當(dāng)前的計算機系統(tǒng)中, 代碼和數(shù)據(jù)沒有本質(zhì)差別, 都是一串二進(jìn)制數(shù), 區(qū)別只在于你如何用它. 例如, CS 制定的段總是被用作代碼, 一般不能通過CS指定的地址去修改該段. 然而,你可以為同一個段申請一個數(shù)據(jù)段描述符別名而通過DS來訪問/修改. 自修改代碼的程序常如此做.ES,FS,GS 是輔助的段寄存器, 指定附加的數(shù)據(jù)段.SS(STACK SEGMENT)指定當(dāng)前堆棧段. ESP 則指出該段中當(dāng)前的堆棧頂. 所有push/pop 系列指令都只對SS:ESP指出的地址進(jìn)行操作.3. 標(biāo)志寄存器(EFLAGS):該寄存器有32位,組合了各個系統(tǒng)標(biāo)志. EFLAGS一般不作為整體訪問, 而只對單一的標(biāo)志位感興趣. 常用的標(biāo)志有: 進(jìn)位標(biāo)志C(CARRY), 在加法產(chǎn)生進(jìn)位或減法有借位時置1, 否則為0.零標(biāo)志Z(ZERO), 若運算結(jié)果為0則置1, 否則為0符號位S(SIGN), 若運算結(jié)果的最高位置1, 則該位也置1. 溢出標(biāo)志O(OVERFLOW), 若(帶符號)運算結(jié)果超出可表示范圍, 則置1. JXX 系列指令就是根據(jù)這些標(biāo)志來決定是否要跳轉(zhuǎn), 從而實現(xiàn)條件分枝. 要注意,很多JXX 指令是等價的, 對應(yīng)相同的機器碼. 例如, JE 和JZ 是一樣的,都是當(dāng)Z=1是跳轉(zhuǎn). 只有JMP 是無條件跳轉(zhuǎn). JXX 指令分為兩組, 分別用于無符號操作和帶符號操作. JXX 后面的XX 有如下字母:無符號操作: 帶符號操作:A = ABOVE, 表示高于 G = GREATER, 表示大于B = BELOW, 表示低于 L = LESS, 表示小于C = CARRY, 表示進(jìn)位或借位 O = OVERFLOW, 表示溢出S = SIGN, 表示負(fù)通用符號:E = EQUAL 表示等于, 等價于Z (ZERO)N = NOT 表示非, 即標(biāo)志沒有置位. 如JNZ 如果Z沒有置位則跳轉(zhuǎn)Z = ZERO, 與E同.如果仔細(xì)想一想,就會發(fā)現(xiàn) JA = JNBE, JAE = JNB, JBE = JNA, JG = JNLE, JGE= JNL, JL= JNGE, .4. 端口端口是直接和外部設(shè)備通訊的地方。外設(shè)接入系統(tǒng)后,系統(tǒng)就會把外設(shè)的數(shù)據(jù)接口映射到特定的端口地址空間,這樣,從該端口讀入數(shù)據(jù)就是從外設(shè)讀入數(shù)據(jù),而向外設(shè)寫入數(shù)據(jù)就是向端口寫入數(shù)據(jù)。當(dāng)然這一切都必須遵循外設(shè)的工作方式。端口的地址空間與內(nèi)存地址空間無關(guān),系統(tǒng)總共提供對64K個8位端口的訪問,編號0-65535. 相鄰的8位端口可以組成成一個16位端口,相鄰的16位端口可以組成一個32位端口。端口輸入輸出由指令I(lǐng)N,OUT,INS和OUTS實現(xiàn),具體可參考匯編語言書籍。匯編指令的操作數(shù)可以是內(nèi)存中的數(shù)據(jù), 如何讓程序從內(nèi)存中正確取得所需要的數(shù)據(jù)就是對內(nèi)存的尋址。 INTEL 的CPU 可以工作在兩種尋址模式:實模式和保護(hù)模式。 前者已經(jīng)過時,就不講了, WINDOWS 現(xiàn)在是32位保護(hù)模式的系統(tǒng), PE 文件就基本是運行在一個 32位線性地址空間, 所以這里就只介紹32位線性空間的尋址方式。 其實線性地址的概念是很直觀的, 就想象一系列字節(jié)排成一長隊,第一個字節(jié)編號為0, 第二個編號位1, 。 一直到4294967295(十六進(jìn)制FFFFFFFF,這是32位二進(jìn)制數(shù)所能表達(dá)的最大值了)。 這已經(jīng)有4GB的容量! 足夠容納一個程序所有的代碼和數(shù)據(jù)。 當(dāng)然, 這并不表示你的機器有那么多內(nèi)存。 物理內(nèi)存的管理和分配是很復(fù)雜的內(nèi)容, 初學(xué)者不必在意, 總之, 從程序本身的角度看, 就好象是在那么大的內(nèi)存中。 在INTEL系統(tǒng)中, 內(nèi)存地址總是由段選擇符:有效地址的方式給出。段選擇符(SELECTOR)存放在某一個段寄存器中, 有效地址則可由不同的方式給出。 段選擇符通過檢索段描述符確定段的起始地址, 長度(又稱段限制), 粒度, 存取權(quán)限, 訪問性質(zhì)等。 先不用深究這些, 只要知道段選擇符可以確定段的性質(zhì)就行了。 一旦由選擇符確定了段, 有效地址相對于段的基地址開始算。 比如由選擇符1A7選擇的數(shù)據(jù)段, 其基地址是400000, 把1A7 裝入DS中, 就確定使用該數(shù)據(jù)段。 DS:0 就指向線性地址400000。 DS:1F5278 就指向線性地址5E5278。 我們在一般情況下, 看不到也不需要看到段的起始地址, 只需要關(guān)心在該段中的有效地址就行了。 在32位系統(tǒng)中, 有效地址也是由32位數(shù)字表示, 就是說, 只要有一個段就足以涵蓋4GB線性地址空間, 為什么還要有不同的段選擇符呢? 正如前面所說的, 這是為了對數(shù)據(jù)進(jìn)行不同性質(zhì)的訪問。 非法的訪問將產(chǎn)生異常中斷, 而這正是保護(hù)模式的核心內(nèi)容, 是構(gòu)造優(yōu)先級和多任務(wù)系統(tǒng)的基礎(chǔ)。 這里有涉及到很多深層的東西, 初學(xué)者先可不必理會。 有效地址的計算方式是: 基址+間址*比例因子+偏移量。 這些量都是指段內(nèi)的相對于段起始地址的量度, 和段的起始地址沒有關(guān)系。 比如, 基址=100000, 間址=400, 比例因子=4, 偏移量=20000, 則有效地址為: 100000+400*4+20000=100000+1000+20000=121000。 對應(yīng)的線性地址是400000+121000=521000。 (注意, 都是十六進(jìn)制數(shù))。 基址可以放在任何32位通用寄存器中, 間址也可以放在除ESP外的任何一個通用寄存器中。 比例因子可以是1, 2, 4 或8。 偏移量是立即數(shù)。 如: EBP+EDX*8+200就是一個有效的有效地址表達(dá)式。 當(dāng)然, 多數(shù)情況下用不著這么復(fù)雜, 間址,比例因子和偏移量不一定要出現(xiàn)。 內(nèi)存的基本單位是字節(jié)(BYTE)。 每個字節(jié)是8個二進(jìn)制位, 所以每個字節(jié)能表示的最大的數(shù)是11111111, 即十進(jìn)制的255。 一般來說, 用十六進(jìn)制比較方便, 因為每4個二進(jìn)制位剛好等于1個十六進(jìn)制位, 11111111b = 0xFF。 內(nèi)存中的字節(jié)是連續(xù)存放的, 兩個字節(jié)構(gòu)成一個字(WORD), 兩個字構(gòu)成一個雙字(DWORD)。 在INTEL架構(gòu)中, 采用small endian格式, 即在內(nèi)存中,高位字節(jié)在低位字節(jié)后面。 舉例說明:十六進(jìn)制數(shù)803E7D0C, 每兩位是一個字節(jié), 在內(nèi)存中的形式是: 0C 7D 3E 80。 在32位寄存器中則是正常形式,如在EAX就是803E7D0C。 當(dāng)我們的形式地址指向這個數(shù)的時候,實際上是指向第一個字節(jié),即0C。 我們可以指定訪問長度是字節(jié), 字或者雙字。 假設(shè)DS:EDX指向第一個字節(jié)0C: mov AL, byte ptr DS:EDX ;把字節(jié)0C存入AL mov AX, word ptr DS:EDX ;把字7D0C存入AX mov EAX, dword ptr DS:EDX ;把雙字803E7D0C存入EAX 在段的屬性中,有一個就是缺省訪問寬度。如果缺省訪問寬度為雙字(在32位系統(tǒng)中經(jīng)常如此),那么要進(jìn)行字節(jié)或字的訪問,就必須用byte/word ptr顯式地指明。 缺省段選擇:如果指令中只有作為段內(nèi)偏移的有效地址,而沒有指明在哪一個段里的時候,有如下規(guī)則: 如果用ebp和esp作為基址或間址,則認(rèn)為是在SS確定的段中; 其他情況,都認(rèn)為是在DS確定的段中。 如果想打破這個規(guī)則,就必須使用段超越前綴。舉例如下: mov eax, dword ptr edx ;缺省使用DS,把DS:EDX指向的雙字送入eax mov ebx, dword ptr ES:EDX ;使用ES:段超越前綴,把ES:EDX指向的雙字送入ebx 堆棧: 堆棧是一種數(shù)據(jù)結(jié)構(gòu),嚴(yán)格地應(yīng)該叫做“?!??!岸选笔橇硪环N類似但不同的結(jié)構(gòu)。SS 和 ESP 是INTEL對棧這種數(shù)據(jù)結(jié)構(gòu)的硬件支持。push/pop指令是專門針對棧結(jié)構(gòu)的特定操作。SS指定一個段為棧段,ESP則指出當(dāng)前的棧頂。push xxx 指令作如下操作: 把ESP的值減去4; 把xxx存入SS:ESP指向的內(nèi)存單元。 這樣,esp的值減小了4,并且SS:ESP指向新壓入的xxx。 所以棧是“倒著長”的,從高地址向低地址方向擴展。pop yyy 指令做相反的操作,把SS:ESP指向的雙字送到y(tǒng)yy指定的寄存器或內(nèi)存單元,然后把esp的值加上4。這時,認(rèn)為該值已被彈出,不再在棧上了,因為它雖然還暫時存在在原來的棧頂位置,但下一個push操作就會把它覆蓋。因此,在棧段中地址低于esp的內(nèi)存單元中的數(shù)據(jù)均被認(rèn)為是未定義的。 最后,有一個要注意的事實是,匯編語言是面向機器的,指令和機器碼基本上是一一對應(yīng)的,所以它們的實現(xiàn)取決于硬件。有些看似合理的指令實際上是不存在的,比如: mov DS:edx, ds:ecx ;內(nèi)存單元之間不能直接傳送 mov DS, 1A7 ;段寄存器不能直接由立即數(shù)賦值 mov EIP, 3D4E7 ;不能對指令指針直接操作。高級語言程序的匯編解析 在高級語言中,如C和PASCAL等等,我們不再直接對硬件資源進(jìn)行操作,而是面向于問題的解決,這主要體現(xiàn)在數(shù)據(jù)抽象化和程序的結(jié)構(gòu)化。例如我們用變量名來存取數(shù)據(jù),而不再關(guān)心這個數(shù)據(jù)究竟在內(nèi)存的什么地方。這樣,對硬件資源的使用方式完全交給了編譯器去處理。不過,一些基本的規(guī)則還是存在的,而且大多數(shù)編譯器都遵循一些規(guī)范,這使得我們在閱讀反匯編代碼的時候日子好過一點。這里主要講講匯編代碼中一些和高級語言對應(yīng)的地方。 1. 普通變量。通常聲明的變量是存放在內(nèi)存中的。編譯器把變量名和一個內(nèi)存地址聯(lián)系起來(這里要注意的是,所謂的“確定的地址”是對編譯器而言在編譯階段算出的一個臨時的地址。在連接成可執(zhí)行文件并加載到內(nèi)存中執(zhí)行的時候要進(jìn)行重定位等一系列調(diào)整,才生成一個實時的內(nèi)存地址,不過這并不影響程序的邏輯,所以先不必太在意這些細(xì)節(jié),只要知道所有的函數(shù)名字和變量名字都對應(yīng)一個內(nèi)存的地址就行了),所以變量名在匯編代碼中就表現(xiàn)為一個有效地址,就是放在方括號中的操作數(shù)。例如,在C文件中聲明: int my_age; 這個整型的變量就存在一個特定的內(nèi)存位置。語句 my_age= 32; 在反匯編代碼中可能表現(xiàn)為: mov word ptr 007E85DA, 20 所以在方括號中的有效地址對應(yīng)的是變量名。又如: char my_name11 = lianzi2000; 這樣的說明也確定了一個地址,對應(yīng)于my_name. 假設(shè)地址是007E85DC,則內(nèi)存中007E85DC=l,007E85DD=i, etc. 對my_name的訪問也就是對這地址處的數(shù)據(jù)訪問。 指針變量其本身也同樣對應(yīng)一個地址,因為它本身也是一個變量。如: char *your_name; 這時也確定變量your_name對應(yīng)一個內(nèi)存地址,假設(shè)為007E85F0. 語句your_name=my_name;很可能表現(xiàn)為: mov 007E85F0, 007E85DC ;your_name的內(nèi)容是my_name的地址。 2. 寄存器變量 在C和C+中允許說明寄存器變量。register int i; 指明i是寄存器存放的整型變量。通常,編譯器都把寄存器變量放在esi和edi中。寄存器是在cpu內(nèi)部的結(jié)構(gòu),對它的訪問要比內(nèi)存快得多,所以把頻繁使用的變量放在寄存器中可以提高程序執(zhí)行速度。 3. 數(shù)組 不管是多少維的數(shù)組,在內(nèi)存中總是把所有的元素都連續(xù)存放,所以在內(nèi)存中總是一維的。例如,int i_array23; 在內(nèi)存確定了一個地址,從該地址開始的12個字節(jié)用來存貯該數(shù)組的元素。所以變量名i_array對應(yīng)著該數(shù)組的起始地址,也即是指向數(shù)組的第一個元素。存放的順序一般是i_array00,01,02,10,11,12 即最右邊的下標(biāo)變化最快。當(dāng)需要訪問某個元素時,程序就會從多維索引值換算成一維索引,如訪問i_array11,換算成內(nèi)存中的一維索引值就是1*3+1=4.這種換算可能在編譯的時候就可以確定,也可能要到運行時才可以確定。無論如何,如果我們把i_array對應(yīng)的地址裝入一個通用寄存器作為基址,則對數(shù)組元素的訪問就是一個計算有效地址的問題: ; i_array11=0x16 lea ebx,xxxxxxxx ;i_array 對應(yīng)的地址裝入ebx mov edx,04 ;訪問i_array11,編譯時就已經(jīng)確定 mov word ptr ebx+edx*2, 16 ; 當(dāng)然,取決于不同的編譯器和程序上下文,具體實現(xiàn)可能不同,但這種基本的形式是確定的。從這里也可以看到比例因子的作用(還記得比例因子的取值為1,2,4或8嗎?),因為在目前的系統(tǒng)中簡單變量總是占據(jù)1,2,4或者8個字節(jié)的長度,所以比例因子的存在為在內(nèi)存中的查表操作提供了極大方便。 4. 結(jié)構(gòu)和對象 結(jié)構(gòu)和對象的成員在內(nèi)存中也都連續(xù)存放,但有時為了在字邊界或雙字邊界對齊,可能有些微調(diào)整,所以要確定對象的大

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論