版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第三章程序的轉(zhuǎn)換及機器級表示
程序轉(zhuǎn)換概述
IA-32指令系統(tǒng)
C語言程序的機器級表示
復(fù)雜數(shù)據(jù)類型的分配和訪問
x86-64架構(gòu)程序的轉(zhuǎn)換與機器級表示主要教學(xué)目標(biāo)了解高級語言與匯編語言、匯編語言與機器語言之間的關(guān)系掌握有關(guān)指令格式、操作數(shù)類型、尋址方式、操作類型等內(nèi)容了解高級語言源程序中的語句與機器級代碼之間的對應(yīng)關(guān)系了解復(fù)雜數(shù)據(jù)類型(數(shù)組、結(jié)構(gòu)等)的機器級實現(xiàn)主要教學(xué)內(nèi)容介紹C語言程序與IA-32機器級指令之間的對應(yīng)關(guān)系。主要包括:程序轉(zhuǎn)換概述、IA-32指令系統(tǒng)、C語言中控制語句和過程調(diào)用等機器級實現(xiàn)、復(fù)雜數(shù)據(jù)類型(數(shù)組、結(jié)構(gòu)等)的機器級實現(xiàn)等。本章所用的機器級表示主要以匯編語言形式表示為主。采用逆向工程方法!程序的機器級表示分以下五個部分介紹第一講:程序轉(zhuǎn)換概述機器指令和匯編指令機器級程序員感覺到的屬性和功能特性高級語言程序轉(zhuǎn)換為機器代碼的過程第二講:IA-32指令系統(tǒng)第三講:C語言程序的機器級表示過程調(diào)用的機器級表示選擇語句的機器級表示循環(huán)結(jié)構(gòu)的機器級表示第四講:復(fù)雜數(shù)據(jù)類型的分配和訪問數(shù)組的分配和訪問結(jié)構(gòu)體數(shù)據(jù)的分配和訪問聯(lián)合體數(shù)據(jù)的分配和訪問數(shù)據(jù)的對齊第五講:x86-64指令系統(tǒng)從高級語言程序出發(fā),用其對應(yīng)的機器級代碼以及內(nèi)存(棧)中信息的變化來說明底層實現(xiàn)圍繞C語言中的語句和復(fù)雜數(shù)據(jù)類型,解釋其在底層機器級的實現(xiàn)方法回顧:Hardware/SoftwareInterface…,EXTop=1,ALUSelA=1,ALUSelB=11,ALUop=add,IorD=1,Read,MemtoReg=1,RegWr=1,......temp=v[k];v[k]=v[k+1];v[k+1]=temp;lw$15,0($2)lw$16,4($2)sw$16,0($2)sw$15,4($2)10001100010011110000000000000000100011000101000000000000000001001010110001010000000000000000000010101100010011110000000000000100軟件硬件匯編指令機器指令…11111001011…微指令swap0($2),4($2)偽指令“指令”的概念計算機中有微指令、機器指令和偽(宏)指令之分微指令是微程序級命令,屬于硬件范疇偽指令是由若干機器指令組成的指令序列,屬于軟件范疇機器指令介于二者之間,處于硬件和軟件的交界面本章中提及的指令都指機器指令匯編指令是機器指令的匯編表示形式,即符號表示機器指令和匯編指令一一對應(yīng),它們都與具體機器結(jié)構(gòu)有關(guān),都屬于機器級指令
機器級指令機器指令和匯編指令一一對應(yīng),都是機器級指令機器指令是一個0/1序列,由若干字段組成匯編指令是機器指令的符號表示(可能有不同的格式)mov、movb、bx、%bx等都是助記符指令的功能為:M[R[bx]+R[di]-6]←R[cl]
操作碼尋址方式寄存器編號立即數(shù)(位移量)mov[bx+di-6],clmovb%cl,-6(%bx,%di)或Intel格式AT&T格式補碼11111010的真值為多少?寄存器傳送語言RTL(RegisterTransferLanguage)
R:寄存器內(nèi)容M:存儲單元內(nèi)容
本課程采用AT&T格式操作碼:opcode;w:與機器模式(16/32位)一起確定寄存器位數(shù)(AL/AX/EAX);d:操作方向?qū)ぶ贩绞剑簃od、r/m、reg/op三個字段與w字段和機器模式一起確定操作數(shù)所在的寄存器編號或有效地址計算方式SIB中基址B和變址I都可是8個GRS中任一個;SS給出比例因子位移量和立即數(shù)的長度可以是:1B(8位)、2B(16位)、4B(32位)IA-32機器指令格式回顧:計算機中數(shù)據(jù)的存儲計算機中的數(shù)據(jù)存放在哪里?寄存器文件通用寄存器組GPRs存儲器指令中需給出的信息:操作性質(zhì)(操作碼)源操作數(shù)1或/和源操作數(shù)2
(立即數(shù)、寄存器編號、存儲地址)目的操作數(shù)地址(寄存器編號、存儲地址)存儲地址的描述與操作數(shù)的數(shù)據(jù)結(jié)構(gòu)有關(guān)!相當(dāng)于宿舍書架相當(dāng)于圖書館書架I/OCPUCompilerOperatingSystemApplicationDigitalDesignCircuitDesignInstructionSetArchitectureMMAssembler回顧:指令集體系結(jié)構(gòu)ISAISA(InstructionSetArchitecture)位于軟件和硬件之間硬件的功能通過ISA提供出來軟件通過ISA規(guī)定的”指令”使用硬件ISA規(guī)定了:可執(zhí)行的指令的集合,包括指令格式、操作種類以及每種操作對應(yīng)的操作數(shù)的相應(yīng)規(guī)定;指令可以接受的操作數(shù)的類型;操作數(shù)所能存放的寄存器組的結(jié)構(gòu),包括每個寄存器的名稱、編號、長度和用途;操作數(shù)所能存放的存儲空間的大小和編址方式;操作數(shù)在存儲空間存放時按照大端還是小端方式存放;指令獲取操作數(shù)的方式,即尋址方式;指令執(zhí)行過程的控制方式,包括程序計數(shù)器、條件碼定義等。高級語言程序轉(zhuǎn)換為機器代碼的過程
預(yù)處理:在高級語言源程序中插入所有用#include命令指定的文件和用#define聲明指定的宏。編譯:將預(yù)處理后的源程序文件編譯生成相應(yīng)的匯編語言程序。匯編:由匯編程序?qū)R編語言源程序文件轉(zhuǎn)換為可重定位的機器語言目標(biāo)代碼文件。鏈接:由鏈接器將多個可重定位的機器語言目標(biāo)文件以及庫例程(如printf()庫函數(shù))鏈接起來,生成最終的可執(zhí)行目標(biāo)文件。用GCC編譯器套件進行轉(zhuǎn)換的過程GCC使用舉例兩個源程序文件test1.c和test2.c,最終生成可執(zhí)行文件為testgcc-O1test1.ctest2.c-otest選項-O1表示一級優(yōu)化,-O2為二級優(yōu)化,選項-o指出輸出文件名add:pushl %ebpmovl %esp,%ebpsubl $16,%espmovl 12(%ebp),%eaxmovl 8(%ebp),%edxleal (%edx,%eax),%eaxmovl %eax,-4(%ebp)movl -4(%ebp),%eaxleaveret00000000<add>:0:55 push%ebp1:89e5 mov%esp,%ebp3:83ec10sub$0x10,%esp6:8b450cmov0xc(%ebp),%eax9:8b5508mov0x8(%ebp),%edxc:8d0402lea(%edx,%eax,1),%eaxf:8945fcmov%eax,-0x4(%ebp)12:8b45fcmov-0x4(%ebp),%eax15:c9leave16:c3retgcc-Etest.c-otest.igcc-Stest.i-otest.s
gcc–Stest.c–otest.s
test.s位移量機器指令匯編指令編譯得到的與反匯編得到的匯編指令形式稍有差異“gcc–ctest.s–otest.o”將test.s匯編為test.o“objdump-dtest.o”將test.o反匯編為
兩種目標(biāo)文件“objdump-dtest”結(jié)果00000000<add>:0:55 push%ebp1:89e5 mov%esp,%ebp3:83ec10sub$0x10,%esp6:8b450cmov0xc(%ebp),%eax9:8b5508mov0x8(%ebp),%edxc:8d0402lea(%edx,%eax,1),%eaxf:8945fcmov%eax,-0x4(%ebp)12:8b45fcmov-0x4(%ebp),%eax15:c9leave16:c3rettest.o中的代碼從地址0開始,test中的代碼從80483d4開始!080483d4<add>:80483d4:55push...80483d5:89e5…80483d7:83ec10…80483da:8b450c…80483dd:8b5508…80483e0:8d0402…80483e3:8945fc…80483e6:8b45fc…80483e9:c9…80483ea:c3
ret
“objdump-dtest.o”結(jié)果test.o:可重定位目標(biāo)文件test:可執(zhí)行目標(biāo)文件可執(zhí)行文件的存儲器映像0ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫區(qū)域堆(heap)(由malloc動態(tài)生成)用戶棧(Userstack)動態(tài)生成未使用0讀寫數(shù)據(jù)段(.data,.bss)只讀代碼段(.init,.text,.rodata)從可執(zhí)行文件裝入程序(段)頭表描述如何映射ELF頭程序(段)頭表.text節(jié).data節(jié).bss節(jié).symtab節(jié).debug節(jié).rodata節(jié).line節(jié).init節(jié).strtab節(jié)1GB
從高地址向低地址增長!程序的機器級表示分以下五個部分介紹第一講:程序轉(zhuǎn)換概述機器指令和匯編指令機器級程序員感覺到的屬性和功能特性高級語言程序轉(zhuǎn)換為機器代碼的過程第二講:IA-32指令系統(tǒng)第三講:C語言程序的機器級表示過程調(diào)用的機器級表示選擇語句的機器級表示循環(huán)結(jié)構(gòu)的機器級表示第四講:復(fù)雜數(shù)據(jù)類型的分配和訪問數(shù)組的分配和訪問結(jié)構(gòu)體數(shù)據(jù)的分配和訪問聯(lián)合體數(shù)據(jù)的分配和訪問數(shù)據(jù)的對齊第五講:x86-64指令系統(tǒng)從高級語言程序出發(fā),用其對應(yīng)的機器級代碼以及內(nèi)存(棧)中信息的變化來說明底層實現(xiàn)圍繞C語言中的語句和復(fù)雜數(shù)據(jù)類型,解釋其在底層機器級的實現(xiàn)方法IA-32/x64指令系統(tǒng)概述x86是Intel開發(fā)的一類處理器體系結(jié)構(gòu)的泛稱包括Intel8086、80286、i386和i486等,因此其架構(gòu)被稱為“x86”由于數(shù)字并不能作為注冊商標(biāo),因此,后來使用了可注冊的名稱,如Pentium、PentiumPro、Core2、Corei7等現(xiàn)在Intel把32位x86架構(gòu)的名稱x86-32改稱為IA-32由AMD首先提出了一個兼容IA-32指令集的64位版本擴充了指令及寄存器長度和個數(shù)等,更新了參數(shù)傳送方式AMD稱其為AMD64,Intel稱其為Intl64(不同于IA-64)命名為“x86-64”,有時也簡稱為x64本課程主要介紹IA-32,最后簡要介紹x-64回顧:計算機系統(tǒng)核心層之間的關(guān)聯(lián)前端遵循語言規(guī)范高級語言程序詞法、語法及語義分析中間代碼生成中間代碼目標(biāo)代碼生成及優(yōu)化目標(biāo)代碼后端遵循ISA規(guī)范和ABI規(guī)范后端根據(jù)ISA規(guī)范和應(yīng)用程序二進制接口(ApplicationBinaryInterface,ABI)規(guī)范進行設(shè)計實現(xiàn)。ABI是為運行在特定ISA及特定操作系統(tǒng)之上的應(yīng)用程序規(guī)定的一種機器級目標(biāo)代碼層接口描述了應(yīng)用程序和操作系統(tǒng)之間、應(yīng)用程序和所調(diào)用的庫之間、不同組成部分(如過程或函數(shù))之間在較低層次上的機器級代碼接口。運行平臺:操作系統(tǒng)+ISA架構(gòu)本課程所用平臺為IA-32/x86-64+Linux+GCC+C語言,Linux操作系統(tǒng)下一般使用systemVABI同一個C語言源程序,使用遵循不同ABI規(guī)范的編譯器進行編譯,其執(zhí)行結(jié)果可能不一樣。程序員將程序移植到另一個系統(tǒng)時,一定要仔細閱讀目標(biāo)系統(tǒng)的ABI規(guī)范。I386SystemVABI規(guī)定的數(shù)據(jù)類型IA-32的寄存器組織8個通用寄存器兩個專用寄存器6個段寄存器IA-32的標(biāo)志寄存器EFLAGS6個條件標(biāo)志OF、SF、ZF、CF各是什么標(biāo)志(條件碼)?AF:輔助進位標(biāo)志(BCD碼運算時才有意義)PF:奇偶標(biāo)志3個控制標(biāo)志DF(DirectionFlag):方向標(biāo)志(自動變址方向是增還是減)IF(InterruptFlag):中斷允許標(biāo)志(僅對外部可屏蔽中斷有用)TF(TrapFlag):陷阱標(biāo)志(是否是單步跟蹤狀態(tài))……808680286/386X87浮點指令、MMX和SSE指令I(lǐng)A-32的浮點處理架構(gòu)有兩種:浮點協(xié)處理器x87架構(gòu)(x87FPU)8個80位寄存器ST(0)~ST(7)(采用棧結(jié)構(gòu)),棧頂為ST(0)由MMX發(fā)展而來的SSE架構(gòu)MMX指令使用8個64位寄存器MM0~MM7,借用8個80位寄存器ST(0)~ST(7)中64位尾數(shù)所占的位,可同時處理8個字節(jié),或4個字,或2個雙字,或一個64位的數(shù)據(jù)MMX指令并沒帶來3D游戲性能的顯著提升,故相繼推出SSE指令集,它們都采用SIMD(單指令多數(shù)據(jù),也稱數(shù)據(jù)級并行)技術(shù)SSE指令集將80位浮點寄存器擴充到128位多媒體擴展通用寄存器XMM0~XMM7,可同時處理16個字節(jié),或8個字,或4個雙字(32位整數(shù)或單精度浮點數(shù)),或兩個四字的數(shù)據(jù),而且從SSE2開始,還支持128位整數(shù)運算或同時并行處理兩個64位雙精度浮點數(shù)IA-32中通用寄存器中的編號反映了體系結(jié)構(gòu)發(fā)展的軌跡,字長不斷擴充,指令保持兼容ST(0)~ST(7)是80位,MM0~MM7使用其低64位IA-32的尋址方式尋址方式根據(jù)指令給定信息得到操作數(shù)或操作數(shù)地址操作數(shù)所在的位置指令中:立即尋址寄存器中:寄存器尋址存儲單元中(屬于存儲器操作數(shù),按字節(jié)編址):其他尋址方式存儲器操作數(shù)的尋址方式與微處理器的工作模式有關(guān)兩種工作模式:實地址模式和保護模式實地址模式(基本用不到)為與8086/8088兼容而設(shè),加電或復(fù)位時尋址空間為1MB,20位地址:(CS)<<4+(IP)保護模式(需要掌握)加電后進入,采用虛擬存儲管理,多任務(wù)情況下隔離、保護80286以上高檔微處理器最常用的工作模式尋址空間為232B,32位地址分段(段基址+段內(nèi)偏移量)保護模式下的尋址方式SR段寄存器(間接)確定操作數(shù)所在段的段基址有效地址給出操作數(shù)在所在段的偏移地址尋址過程涉及到“分段虛擬管理方式”,將在第6章討論存儲器操作數(shù)跳轉(zhuǎn)目標(biāo)指令地址存儲器操作數(shù)的尋址方式intx;floata[100];shortb[4][4];charc;doubled[10];a[i]的地址如何計算?104+i×4i=99時,104+99×4=500b[i][j]的地址如何計算?504+i×8+j×2i=3、j=2時,504+24+4=532d[i]的地址如何計算?544+i×8i=9時,544+9×8=616b31 b0xa[0]a[99]b[0][1]100104b[0][0]b[3][3]b[3][2]c500504532536544d[0]d[9]616存儲器操作數(shù)的尋址方式各變量應(yīng)采用什么尋址方式?x、c:位移/基址a[i]:104+i×4,比例變址+位移d[i]:544+i×8,比例變址+位移b[i][j]:504+i×8+j×2,基址+比例變址+位移intx;floata[100];shortb[4][4];charc;doubled[10];
b31 b0xa[0]a[99]b[0][1]100104b[0][0]b[3][3]b[3][2]c500504532536544d[0]d[9]616將b[i][j]取到AX中的指令可以是:“movw504(%ebp,%esi,2),%ax”其中,
i×8在EBP中,j在ESI中,
2為比例因子IA-32常用指令類型(1)傳送指令通用數(shù)據(jù)傳送指令MOV:一般傳送,包括movb、movw和movl等MOVS:符號擴展傳送,如movsbw、movswl等MOVZ:零擴展傳送,如movzwl、movzbl等XCHG:數(shù)據(jù)交換PUSH/POP:入棧/出棧,如pushl,pushw,popl,popw等地址傳送指令LEA:加載有效地址,如leal(%edx,%eax),%eax”的功能為R[eax]←R[edx]+R[eax],執(zhí)行前,若R[edx]=i,R[eax]=j,則指令執(zhí)行后,R[eax]=i+j輸入輸出指令I(lǐng)N和OUT:I/O端口與寄存器之間的交換標(biāo)志傳送指令PUSHF、POPF:將EFLAG壓棧,或?qū)m攦?nèi)容送EFLAG
“入?!焙汀俺鰲!辈僮鳁#⊿tack)是一種采用“先進后出”方式進行訪問的一塊存儲區(qū),用于嵌套過程調(diào)用。從高地址向低地址增長“?!辈坏扔凇岸褩!保ㄓ伞岸选焙汀皸!苯M成)棧底棧底R[sp]←R[sp]-2、M[R[sp]]←R[ax]R[ax]←M[R[sp]]、[sp]←R[sp]+2為什么AL在棧頂?小端方式!傳送指令舉例將以下Intel格式指令轉(zhuǎn)換為AT&T格式指令,并說明功能。push ebp mov ebp,espmov edx,DWORDPTR[ebp+8]mov bl,255mov ax,WORDPTR[ebp+edx*4+8]mov WORDPTR[ebp+20],dxlea eax,[ecx+edx*4+8]pushl %ebp //R[esp]←R[esp]-4,M[R[esp]]←R[ebp],雙字movl %esp,%ebp //R[ebp]←R[esp],雙字movl 8(%ebp),%edx//R[edx]←M[R[ebp]+8],雙字movb $255,%bl //R[bl]←255,字節(jié)movw 8(%ebp,%edx,4),%ax//R[ax]←M[R[ebp]+R[edx]×4+8],字movw %dx,20(%ebp) //M[R[ebp]+20]←R[dx],字leal 8(%ecx,%edx,4),%eax//R[eax]←R[ecx]+R[edx]×4+8,雙字IA-32常用指令類型(2)定點算術(shù)運算指令加/減運算(影響標(biāo)志、不區(qū)分無/帶符號)ADD:加,包括addb、addw、addl等SUB:減,包括subb、subw、subl等增1/減1運算(影響除CF以外的標(biāo)志、不區(qū)分無/帶符號)INC:加,包括incb、incw、incl等DEC:減,包括decb、decw、decl等取負運算(影響標(biāo)志、若對0取負,則結(jié)果為0且CF=0,否則CF=1)NEG:取負,包括negb、negw、negl等比較運算(做減法得到標(biāo)志、不區(qū)分無/帶符號)CMP:比較,包括cmpb、cmpw、cmpl等乘/除運算(區(qū)分無/帶符號)MUL/IMUL:無符號乘/帶符號乘(影響標(biāo)志OF和CF)DIV/IDIV:帶無符號除/帶符號除整數(shù)乘除指令乘法指令:可給出一個、兩個或三個操作數(shù)若給出一個操作數(shù)SRC,則另一個源操作數(shù)隱含在AL/AX/EAX中,將SRC和累加器內(nèi)容相乘,結(jié)果存放在AX(16位)或DX-AX(32位)或EDX-EAX(64位)中。DX-AX表示32位乘積的高、低16位分別在DX和AX中。n位×n位=2n位若指令中給出兩個操作數(shù)DST和SRC,則將DST和SRC相乘,結(jié)果在DST中。n位×n位=n位若指令中給出三個操作數(shù)REG、SRC和IMM,則將SRC和立即數(shù)IMM相乘,結(jié)果在REG中。n位×n位=n位除法指令:只明顯指出除數(shù)若為8位,則16位被除數(shù)在AX寄存器中,商送回AL,余數(shù)在AH若為16位,則32位被除數(shù)在DX-AX寄存器中,商送回AX,余數(shù)在DX若為32位,則被除數(shù)在EDX-EAX寄存器中,商送EAX,余數(shù)在EDX
以上內(nèi)容不要死記硬背,遇到具體指令時能查閱到并理解即可。定點算術(shù)運算指令匯總定點加法指令舉例假設(shè)R[ax]=FFFAH,R[bx]=FFF0H,則執(zhí)行以下指令后
“addw%bx,%ax”
AX、BX中的內(nèi)容各是什么?標(biāo)志CF、OF、ZF、SF各是什么?要求分別將操作數(shù)作為無符號數(shù)和帶符號整數(shù)解釋并驗證指令執(zhí)行結(jié)果。解:功能:R[ax]←R[ax]+R[bx],指令執(zhí)行后的結(jié)果如下
R[ax]=FFFAH+FFF0H=FFEAH,BX中內(nèi)容不變
CF=1,OF=0,ZF=0,SF=1
若是無符號整數(shù)運算,則CF=1說明結(jié)果溢出驗證:FFFA的真值為65535-5=65530,F(xiàn)FF0的真值為65520FFEA的真值為65535-21=65514≠65530+65520,即溢出
若是帶符號整數(shù)運算,則OF=0說明結(jié)果沒有溢出驗證:FFFA的真值為-6,F(xiàn)FF0的真值為-16FFEA的真值為-22=-6+(-16),結(jié)果正確,無溢出定點乘法指令舉例假設(shè)R[eax]=000000B4H,R[ebx]=00000011H,M[000000F8H]=000000A0H,請問:(1)執(zhí)行指令“mulb%bl”后,哪些寄存器的內(nèi)容會發(fā)生變化?是否與執(zhí)行“imulb%bl”指令所發(fā)生的變化一樣?為什么?請用該例給出的數(shù)據(jù)驗證你的結(jié)論。解:“mulb%bl”功能為R[ax]←R[al]×R[bl],執(zhí)行結(jié)果如下R[ax]=B4H×11H(無符號整數(shù)180和17相乘)
R[ax]=0BF4H,真值為3060=180×17
“imulb%bl”功能為R[ax]←R[al]×R[bl]R[ax]=B4H×11H(帶符號整數(shù)-76和17相乘)若R[ax]=0BF4H,則真值為3060≠-76×17 R[al]=F4H,R[ah]=?AH中的值不一樣!R[ax]=FAF4H,真值為-1292=-76×171011010000010001x10110100101101000000101111110100AL=?AH=?對于帶符號乘,若積只取低n位,則和無符號相同;若取2n位,則采用“布斯”乘法無符號乘:定點乘法指令舉例布斯乘法:10110100001-1001-1000100010x0000000001001100111111110110100000001001100111101101001111101011110100AL=?AH=?R[ax]=FAF4H,真值為-1292=-76×17R[ax]=B4H×11H“imulb%bl”定點乘法指令舉例假設(shè)R[eax]=000000B4H,R[ebx]=00000011H,M[000000F8H]=000000A0H,請問:(2)執(zhí)行指令“imull$-16,(%eax,%ebx,4),%eax”后哪些寄存器和存儲單元發(fā)生了變化?乘積的機器數(shù)和真值各是多少?解:“imull-16,(%eax,%ebx,4),%eax”
功能為R[eax]←(-16)×M[R[eax]+R[ebx]×4],執(zhí)行結(jié)果如下R[eax]+R[ebx]×4=000000B4H+00000011H<<2=000000F8H
R[eax]=(-16)×M[000000F8H]=(-16)×000000A0H(帶符號整數(shù)乘)=FFFFFF60H<<4 =FFFFF600HEAX中的真值為-2560SKIP整數(shù)乘除指令乘法指令:可給出一個、兩個或三個操作數(shù)若給出一個操作數(shù)SRC,則另一個源操作數(shù)隱含在AL/AX/EAX中,將SRC和累加器內(nèi)容相乘,結(jié)果存放在AX(16位)或DX-AX(32位)或EDX-EAX(64位)中。DX-AX表示32位乘積的高、低16位分別在DX和AX中。若指令中給出兩個操作數(shù)DST和SRC,則將DST和SRC相乘,結(jié)果在DST中。若指令中給出三個操作數(shù)REG、SRC和IMM,則將SRC和立即數(shù)IMM相乘,結(jié)果在REG中。除法指令:只明顯指出除數(shù),用EDX-EAX中內(nèi)容除以指定的除數(shù)若為8位,則16位被除數(shù)在AX寄存器中,商送回AL,余數(shù)在AH若為16位,則32位被除數(shù)在DX-AX寄存器中,商送回AX,余數(shù)在DX若為32位,則被除數(shù)在EDX-EAX寄存器中,商送EAX,余數(shù)在EDX
以上內(nèi)容不要死記硬背,遇到具體指令時能查閱到并理解即可。BACKBACKIA-32常用指令類型(3)按位運算指令邏輯運算(僅NOT不影響標(biāo)志,其他指令OF=CF=0,而ZF和SF根據(jù)結(jié)果設(shè)置:若全0,則ZF=1;若最高位為1,則SF=1)NOT:非,包括notb、notw、notl等AND:與,包括andb、andw、andl等OR:或,包括orb、orw、orl等XOR:異或,包括xorb、xorw、xorl等TEST:做“與”操作測試,僅影響標(biāo)志移位運算(左/右移時,最高/最低位送CF)SHL/SHR:邏輯左/右移,包括shlb、shrw、shrl等SAL/SAR:算術(shù)左/右移,左移判溢出,右移高位補符(移位前、后符號位發(fā)生變化,則OF=1)ROL/ROR:循環(huán)左/右移,包括rolb、rorw、roll等RCL/RCR:帶循環(huán)左/右移,將CF作為操作數(shù)一部分循環(huán)移位以上內(nèi)容不要死記硬背,遇到具體指令時能查閱到并理解即可。按位運算指令舉例假設(shè)short型變量x被編譯器分配在寄存器AX中,R[ax]=FF80H,則以下匯編代碼段執(zhí)行后變量x的機器數(shù)和真值分別是多少?
movw%ax,%dxsalw$2,%axaddl%dx,%axsarw$1,%ax解:$2和$1分別表示立即數(shù)2和1。
x是short型變量,故都是算術(shù)移位指令,并進行帶符號整數(shù)加。假設(shè)上述代碼段執(zhí)行前R[ax]=x,則執(zhí)行((x<<2)+x)>>1后,R[ax]=5x/2。算術(shù)左移時,AX中的內(nèi)容在移位前、后符號未發(fā)生變化,故OF=0,沒有溢出。最終AX的內(nèi)容為FEC0H,解釋為short型整數(shù)時,其值為-320。驗證:x=-128,5x/2=-320。經(jīng)驗證,結(jié)果正確。1111111110000000<<21111111110000000+11111110000000001111110110000000>>1=1111111011000000逆向工程:從匯編指令退出高級語言程序代碼移位指令舉例算術(shù)邏輯IA-32常用指令類型(4)控制轉(zhuǎn)移指令
指令執(zhí)行可按順序或跳轉(zhuǎn)到轉(zhuǎn)移目標(biāo)指令處執(zhí)行無條件轉(zhuǎn)移指令JMPDST:無條件轉(zhuǎn)移到目標(biāo)指令DST處執(zhí)行條件轉(zhuǎn)移JccDST:cc為條件碼,根據(jù)標(biāo)志(條件碼)判斷是否滿足條件,若滿足,則轉(zhuǎn)移到目標(biāo)指令DST處執(zhí)行,否則按順序執(zhí)行條件設(shè)置SETccDST:將條件碼cc保存到DST(通常是一個8位寄存器)調(diào)用和返回指令
(用于過程調(diào)用)CALLDST:返回地址RA入棧,轉(zhuǎn)DST處執(zhí)行RET:從棧中取出返回地址RA,轉(zhuǎn)到RA處執(zhí)行中斷指令
(詳見第7、8章)以上內(nèi)容不要死記硬背,遇到具體指令時能查閱到并理解即可。條件轉(zhuǎn)移指令分三類:(1)根據(jù)單個標(biāo)志的值轉(zhuǎn)移(2)按無符號整數(shù)比較轉(zhuǎn)移(3)按帶符號整數(shù)比較轉(zhuǎn)移標(biāo)志信息是干什么的?Ex1:-7-6=-7+(-6)=+36-(-7)=6+7=-3
9-6=3
6-9=1311+000111100010做減法以比較大小,規(guī)則:Unsigned:CF=0時,大于Signed:OF=SF時,大于OF=1、ZF=0SF=0、借位CF=0+1101101001111010OF=1、ZF=0SF=1、借位CF=1例子:C表達式類型轉(zhuǎn)換順序unsignedlonglong↑longlong↑unsigned↑
int↑(unsigned)char,short條件設(shè)置指令SETccDST:將條件碼cc保存到DST(通常是一個8位寄存器)猜測:各用哪種條件設(shè)置指令?charc=-1;d=(a>c)?1:0unsignedshortb=1;unsignedinta=1;d=(b>c)?1:0無符號帶符號例子:程序的機器級表示與執(zhí)行intsum(inta[],unsignedlen){inti,sum=0;for(i=0;i<=len–1;i++) sum+=a[i];returnsum;}當(dāng)參數(shù)len為0時,返回值應(yīng)該是0,但是在機器上執(zhí)行時,卻發(fā)生了存儲器訪問異常。
Why?sum:….L3:…movl-4(%ebp),%eaxmovl12(%ebp),%edxsubl$1,%edxcmpl%edx,%eaxjbe .L3…i在%eax中,len在%edx中%eax:0000……0000%edx:0000……0000subl指令的執(zhí)行結(jié)果是什么?cmpl指令的執(zhí)行結(jié)果是什么?i和len分別存放在哪個寄存器中?%eax?%edx?subl$1,%edx指令的執(zhí)行結(jié)果“subl$1,%edx”執(zhí)行時:A=00000000H,B為00000001H,Sub=1,因此Result是32個1。Result加法器nnnAZFCiConBn01多路選擇器SubBOF加/減運算部件CF=CoSubSF當(dāng)Sub為1時,做減法當(dāng)Sub為0時,做加法已知EDX中為len=00000000Hcpml%edx,%eax指令的執(zhí)行結(jié)果“cmpl%edx,%eax”執(zhí)行時:A=00000000H,B為FFFFFFFFH,Sub=1,因此Result是0…01,CF=1,ZF=0,OF=0,SF=0
Result加法器nnnAZFCiConBn01多路選擇器SubBOF加/減運算部件CF=CoSubSF當(dāng)Sub為1時,做減法當(dāng)Sub為0時,做加法已知EDX中為len-1=FFFFFFFFH
EAX中為i=00000000Hjbe.L3指令的執(zhí)行結(jié)果指令轉(zhuǎn)移條件說明JA/JNBElabelCF=0ANDZF=0無符號數(shù)A>BJAE/JNBlabelCF=0ORZF=1無符號數(shù)A≥BJB/JNAElabelCF=1ANDZF=0無符號數(shù)A<BJBE/JNAlabelCF=1ORZF=1無符號數(shù)A≤BJG/JNLElabelSF=OFANDZF=0有符號數(shù)A>BJGE/JNLlabelSF=OFORZF=1有符號數(shù)A≥BJL/JNGElabelSF≠OFANDZF=0有符號數(shù)A<BJLE/JNGlabelSF≠OFORZF=1有符號數(shù)A≤B“cmpl%edx,%eax”執(zhí)行結(jié)果是
CF=1,ZF=0,OF=0,SF=0,說明滿足條件,應(yīng)轉(zhuǎn)移到.L3執(zhí)行!顯然,對于每個i都滿足條件,因為任何無符號數(shù)都比32個1小,因此循環(huán)體被不斷執(zhí)行,最終導(dǎo)致數(shù)組訪問越界而發(fā)生存儲器訪問異常。例子:程序的機器級表示與執(zhí)行正確的做法是將參數(shù)len聲明為int型。
Why?例:
intsum(inta[],intlen){inti,sum=0;for(i=0;i<=len–1;i++) sum+=a[i];returnsum;}sum:….L3:…movl-4(%ebp),%eaxmovl12(%ebp),%edxsubl$1,%edxcmpl%edx,%eaxjle .L3…i在%eax中,len在%edx中%eax:0000……0000%edx:0000……0000subl指令的執(zhí)行結(jié)果是什么?cmpl指令的執(zhí)行結(jié)果是什么?i和len分別存放在哪個寄存器中?%eax?%edx?jle.L3指令的執(zhí)行結(jié)果指令轉(zhuǎn)移條件說明JA/JNBElabelCF=0ANDZF=0無符號數(shù)A>BJAE/JNBlabelCF=0ORZF=1無符號數(shù)A≥BJB/JNAElabelCF=1ANDZF=0無符號數(shù)A<BJBE/JNAlabelCF=1ORZF=1無符號數(shù)A≤BJG/JNLElabelSF=OFANDZF=0有符號數(shù)A>BJGE/JNLlabelSF=OFORZF=1有符號數(shù)A≥BJL/JNGElabelSF≠OFANDZF=0有符號數(shù)A<BJLE/JNGlabelSF≠OFORZF=1有符號數(shù)A≤B“cmpl%edx,%eax”執(zhí)行結(jié)果是CF=1,ZF=0,OF=0,SF=0,
說明不滿足條件,應(yīng)跳出循環(huán)執(zhí)行,執(zhí)行結(jié)果正常。第一、二講總結(jié)高級語言程序總是轉(zhuǎn)換為機器代碼才能在機器上執(zhí)行轉(zhuǎn)換過程:預(yù)處理、編譯、匯編、鏈接機器代碼是二進制代碼,可DUMP為匯編代碼表示ISA規(guī)定了一臺機器的指令系統(tǒng)涉及到的所有方面,例如:所有指令的指令格式、功能通用寄存器的個數(shù)、位數(shù)、編號和功能存儲地址空間大小、編址方式、大/小端指令尋址方式IA-32是典型的CISC(復(fù)雜指令集計算機)風(fēng)格ISAIntel格式匯編、AT&T格式匯編(本課程使用)指令類型(傳送、算術(shù)、位操作、控制、浮點、…)尋址方式立即、寄存器、存儲器(SR:[B]+[I]*s+A)程序的機器級表示分以下五個部分介紹第一講:程序轉(zhuǎn)換概述機器指令和匯編指令機器級程序員感覺到的屬性和功能特性高級語言程序轉(zhuǎn)換為機器代碼的過程第二講:IA-32指令系統(tǒng)第三講:C語言程序的機器級表示過程調(diào)用的機器級表示選擇語句的機器級表示循環(huán)結(jié)構(gòu)的機器級表示第四講:復(fù)雜數(shù)據(jù)類型的分配和訪問數(shù)組的分配和訪問結(jié)構(gòu)體數(shù)據(jù)的分配和訪問聯(lián)合體數(shù)據(jù)的分配和訪問數(shù)據(jù)的對齊第五講:x86-64指令系統(tǒng)從高級語言程序出發(fā),用其對應(yīng)的機器級代碼以及內(nèi)存(棧)中信息的變化來說明底層實現(xiàn)圍繞C語言中的語句和復(fù)雜數(shù)據(jù)類型,解釋其在底層機器級的實現(xiàn)方法intadd(intx,inty){ returnx+y;}intmain(){ int t1=125;intt2=80; int sum=add(t1,t2); returnsum;}過程調(diào)用的機器級表示以下過程(函數(shù))調(diào)用對應(yīng)的機器級代碼是什么?如何將t1(125)、t2(80)分別傳遞給add中的形式參數(shù)x、yadd函數(shù)執(zhí)行的結(jié)果如何返回給caller?
addmain
main: add:存放參數(shù) 取出參數(shù)調(diào)出add執(zhí)行 執(zhí)行存返回結(jié)果
返回main
為了統(tǒng)一,模塊代碼之間必須遵循調(diào)用接口約定,稱為調(diào)用約定(callingconvention),具體由ABI規(guī)范定義,編譯器強制執(zhí)行,匯編語言程序員也必須強制按照這些約定執(zhí)行,包括寄存器的使用、棧幀的建立和參數(shù)傳遞等??蓤?zhí)行文件的存儲器映像0ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫區(qū)域堆(heap)(由malloc動態(tài)生成)用戶棧(Userstack)動態(tài)生成未使用0讀寫數(shù)據(jù)段(.data,.bss)只讀代碼段(.init,.text,.rodata)從可執(zhí)行文件裝入ELF頭程序(段)頭表.text節(jié).data節(jié).bss節(jié).symtab節(jié).debug節(jié).rodata節(jié).line節(jié).init節(jié).strtab節(jié)1GB
從高地址向低地址增長!IA-32中參數(shù)通過棧來傳遞棧(stack)在哪里?過程調(diào)用的機器級表示
過程調(diào)用的執(zhí)行步驟(P為調(diào)用者,Q為被調(diào)用者)(1)P將入口參數(shù)(實參)放到Q能訪問到的地方;(2)P保存返回地址,然后將控制轉(zhuǎn)移到Q;(3)Q保存P的現(xiàn)場,并為自己的非靜態(tài)局部變量分配空間;(4)執(zhí)行Q的過程體(函數(shù)體);(5)Q恢復(fù)P的現(xiàn)場,釋放局部變量空間;(6)Q取出返回地址,將控制轉(zhuǎn)移到P。結(jié)束階段準(zhǔn)備階段Q過程P過程處理階段CALL指令RET指令
main: add:存放參數(shù) 取出參數(shù)調(diào)出add執(zhí)行 執(zhí)行
存返回結(jié)果
返回main
何為現(xiàn)場?通用寄存器的內(nèi)容!為何要保存現(xiàn)場?因為所有過程共享一套通用寄存器想象:媽媽做菜過程中,讓你來完成其中一個工序時共用一套盤子的情況add(t1,t2)過程調(diào)用的機器級表示
i386SystemVABI規(guī)范約定調(diào)用者保存寄存器:EAX、EDX、ECX
當(dāng)過程P調(diào)用過程Q時,Q可以直接使用這三個寄存器,不用將它們的值保存到棧中。如果P在從Q返回后還要用這三個寄存器的話,P應(yīng)在轉(zhuǎn)到Q之前先保存,并在從Q返回后先恢復(fù)它們的值再使用。被調(diào)用者保存寄存器:EBX、ESI、EDI
Q必須先將它們的值保存到棧中再使用它們,并在返回P之前恢復(fù)它們的值。EBP和ESP分別是幀指針寄存器和棧指針寄存器,分別用來指向當(dāng)前棧幀的底部和頂部。問題:為減少準(zhǔn)備和結(jié)束階段的開銷,每個過程應(yīng)先使用哪些寄存器?EAX、ECX、EDX!相當(dāng)于媽媽騰空的盤子相當(dāng)于媽媽還要用的盤子過程調(diào)用的機器級表示過程調(diào)用過程中棧和棧幀的變化(Q為被調(diào)用過程)①②③④Q(參數(shù)1,…,參數(shù)n);Linux可執(zhí)行文件的存儲映像0ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫區(qū)域堆(heap)(由malloc動態(tài)生成)用戶棧(Userstack)動態(tài)生成未使用0讀寫數(shù)據(jù)段(.data,.bss)只讀代碼段(.init,.text,.rodata)從可執(zhí)行文件裝入程序(段)頭表描述如何映射ELF頭程序(段)頭表.text節(jié).data節(jié).bss節(jié).symtab節(jié).debug節(jié).rodata節(jié).line節(jié).init節(jié).strtab節(jié)1GB
從高地址向低地址增長!一個簡單的過程調(diào)用例子caller:pushl %ebpmovl %esp,%ebpsubl $24,%espmovl $125,-12(%ebp) movl $80,-8(%ebp)movl-8(%ebp),%eaxmovl %eax,4(%esp)movl -12(%ebp),%eax movl %eax,(%esp) call add movl %eax,-4(%ebp) movl -4(%ebp),%eax leave ret
準(zhǔn)備階段結(jié)束階段caller幀底intadd(intx,inty){ returnx+y;}int caller(){ int t1=125;int t2=80; int sum=add(t1,t2); returnsum;}ESP+4分配局部變量準(zhǔn)備入口參數(shù)-4-8-12-16-20返回參數(shù)總在EAX中準(zhǔn)備返回參數(shù)add函數(shù)開始是什么?pushl%ebpmovl%esp,%ebpmovl %ebp,%esppopl %ebp
addcaller
P過程(函數(shù))的結(jié)構(gòu)一個C過程的大致結(jié)構(gòu)如下:準(zhǔn)備階段形成幀底:push指令和mov指令生成棧幀(如果需要的話):sub指令或and指令保存現(xiàn)場(如果有被調(diào)用者保存寄存器):push指令過程(函數(shù))體分配局部變量空間,并賦值具體處理邏輯,如果遇到函數(shù)調(diào)用時準(zhǔn)備參數(shù):將實參送棧幀入口參數(shù)處CALL指令:保存返回地址并轉(zhuǎn)被調(diào)用函數(shù)在EAX中準(zhǔn)備返回參數(shù)結(jié)束階段退棧:leave指令或pop指令取返回地址返回:ret指令入口參數(shù)的位置IA-32中,若參數(shù)類型是unsignedchar、char或unsignedshort、short,也都分配4個字節(jié)故在被調(diào)用函數(shù)中,使用R[ebp]+8、R[ebp]+12、R[ebp]+16作為有效地址來訪問函數(shù)的入口參數(shù)每個過程開始兩條指令pushl%ebpmovl%esp,%ebp返回地址EBP在main中的值EBPEBP+8EBP+12入口參數(shù)1入口參數(shù)2入口參數(shù)3EBP+16movl參數(shù)3,8(%esp)………..movl參數(shù)1,(%esp)calladd準(zhǔn)備入口參數(shù)R[esp]←R[esp]-4M[R[esp]]←返回地址R[eip]←add函數(shù)首地址返回地址是什么?call指令的下一條指令的地址!i386SystemVABI規(guī)范規(guī)定,棧中參數(shù)按4字節(jié)對齊過程調(diào)用參數(shù)傳遞舉例程序一的輸出:a=15 b=22a=22 b=15程序二的輸出:a=15 b=22a=15 b=22程序一#include<stdio.h>main(){inta=15,b=22;printf(“a=%d\tb=%d\n”,a,b);
swap(&a,&b);printf(“a=%d\tb=%d\n”,a,b);}swap(int*x,int*y){ intt=*x; *x=*y; *y=t;}程序二#include<stdio.h>main(){inta=15,b=22;printf(“a=%d\tb=%d\n”,a,b);
swap(a,b);printf(“a=%d\tb=%d\n”,a,b);}swap(intx,inty){ intt=x; x=y; y=t;}按地址傳遞參數(shù)按值傳遞參數(shù)執(zhí)行結(jié)果?為什么?過程調(diào)用參數(shù)傳遞舉例返回地址EBP在main中的值EBPEBP+8EBP+12EBX在main中的值R[ecx]←M[&a]=15R[ebx]←M[&b]=22M[&a]←
R[ebx]=22M[&b]←
R[ecx]=152215局部變量a和b進行了交換過程調(diào)用參數(shù)傳遞舉例返回地址EBP在main中的值EBPEBP+8EBP+12R[edx]←15R[eax]←222215M[R[ebp]+8]←
R[eax]=22M[R[ebp]+12]←
R[edx]=15
局部變量a和b沒有交換,交換的僅是入口參數(shù)過程調(diào)用舉例1voidtest(intx,int*ptr)2{3 if(x>0&&*ptr>0)4 *ptr+=x;5 } 6 7voidcaller(inta,inty)8{9intx=a>0?a:a+100;10 test(x,&y);11}調(diào)用caller的過程為P,P中給出形參a和y的實參分別是100和200,畫出相應(yīng)棧幀中的狀態(tài),并回答下列問題。(1)test的形參是按值傳遞還是按地址傳遞?test的形參ptr對應(yīng)的實參是一個什么類型的值?(2)test中被改變的*ptr的結(jié)果如何返回給它的調(diào)用過程caller?(3)caller中被改變的y的結(jié)果能否返回給過程P?為什么?
testcallerP
caller執(zhí)行過程中,在進入test之前一刻棧中的狀態(tài)如何?進入test并生成其棧幀后,棧中狀態(tài)如何?&y:&a:Pcaller100200300前者按值、后者按地址。一定是一個地址第10行執(zhí)行后,P幀中200變成300,test退幀后,caller中通過y引用該值300第11行執(zhí)行后caller退幀并返回P,因P中無變量與之對應(yīng),故無法引用該值300若returnx+y;則函數(shù)返回400intnn_sum(intn){ intresult; if(n<=0) result=0; else result=n+nn_sum(n-1); returnresult;}遞歸過程調(diào)用舉例nn_sum(n-1)nn_sum(n)PSum(n)Sum(n-1)R[ebx]←nif(n≤0)轉(zhuǎn)L2R[eax]←0R[eax]←n-1R[eax]←0+1+2+…+(n-1)+nn
每次遞歸調(diào)用都會增加一個棧幀(該例為16B),所以空間開銷很大。當(dāng)n很大時會發(fā)生棧溢出!P操作系統(tǒng)為程序分配的棧會有默認的大小限制過程調(diào)用的機器級表示遞歸函數(shù)nn_sum的執(zhí)行流程為支持過程調(diào)用,每個過程包含準(zhǔn)備階段和結(jié)束階段。因而每增加一次過程調(diào)用,就要增加許多條包含在準(zhǔn)備階段和結(jié)束階段的額外指令,它們對程序性能影響很大,應(yīng)盡量避免不必要的過程調(diào)用,特別是遞歸調(diào)用。
非靜態(tài)局部變量的存儲分配非靜態(tài)局部變量占用的空間分配在本過程的棧幀中C標(biāo)準(zhǔn)中,沒有規(guī)定必須按順序分配,不同的編譯器有不同的處理方式。C標(biāo)準(zhǔn)明確指出,對不同變量的地址進行除==和!=之外的關(guān)系運算,都屬未定義行為(undefinedbehavior)如,語句“if(&var1<&var2){...};”屬于未定義行為編譯優(yōu)化的情況下,會把屬于簡單數(shù)據(jù)類型變量分配在通用寄存器中對于復(fù)雜數(shù)據(jù)類型變量,如數(shù)組、結(jié)構(gòu)和聯(lián)合等數(shù)據(jù)類型變量,一定會分配在棧幀中Windows/Linux中的存儲映像說明了什么?注意:每個存儲區(qū)地址的特征!參數(shù)的地址總比局部變量的地址大!因為棧的生長方向:高地址→低地址
局部變量和參數(shù)都存放在:棧區(qū)LinuxWindows
總是最右邊參數(shù)的地址最大,因為參數(shù)入棧順序為:右→左Windows中局部變量的地址不一定連續(xù),也不一定按大小順序分配Windows中的存儲映像#include
……void
__stdcall
func(int
param1,int
param2,int
param3)
{
int
var1=param1;
int
var2=param2;
int
var3=param3;
printf(“0x%08x\n”,¶m1);
printf("0x%08x\n",¶m2);
printf("0x%08x\n\n",¶m3);
printf("0x%08x\n",&var1);
printf("0x%08x\n",&var2);
printf("0x%08x\n\n",&var3);
return;
}
int
main()
{
func(1,2,3);
return
0;
}
執(zhí)行結(jié)果如下:
0x0012ff78
0x0012ff7c
0x0012ff80
0x0012ff68
0x0012ff6c
0x0012ff70
說明了什么?
Windows中棧區(qū)也是高地址向低地址生長!param3=3param2=2param1=1
返回地址var3=3var2=2var1=1猜猜這里是什么?這里與Linux的差別是什么?EBP未壓棧!Windows中的存儲映像#include
….int
g1=0,
g2=0,
g3=0;
int
main()
{
static
int
s1=0,
s2=0,
s3=0;
int
v1=0,
v2=0,
v3=0;
printf("0x%08x\n",&v1);
printf("0x%08x\n",&v2);
printf("0x%08x\n\n",&v3);
printf("0x%08x\n",&g1);
printf("0x%08x\n",&g2);
printf("0x%08x\n\n",&g3);
printf("0x%08x\n",&s1);
printf("0x%08x\n",&s2);
printf("0x%08x\n\n",&s3);
return
0;
}
執(zhí)行結(jié)果如下:0x0012ff78
0x0012ff7c
0x0012ff80
0x004068d0
0x004068d4
0x004068d8
0x004068dc
0x004068e0
0x004068e4說明了什么?注意:每個存儲區(qū)地址的特征!
全局變量和靜態(tài)變量連續(xù)存放在同一個存儲區(qū):可讀寫數(shù)據(jù)區(qū)局部變量存放在另一個存儲區(qū):棧區(qū)Windows/Linux中的存儲映像說明了什么?注意:每個存儲區(qū)地址的特征!全局變量和靜態(tài)變量連續(xù)存放在同一個存儲區(qū):可讀寫數(shù)據(jù)區(qū)
局部變量存放在另一個存儲區(qū):棧區(qū)LinuxWindows選擇結(jié)構(gòu)的機器級表示
if~else語句的機器級表示
if(cond_expr)then_statementelseelse_statement
Jcc指令JMP指令I(lǐng)f-else語句舉例intget_cont(int*p1,int*p2){ if(p1>p2) return*p2; else return*p1;}p1和p2對應(yīng)實參的存儲地址分別為R[ebp]+8、R[ebp]+12,EBP指向當(dāng)前棧幀底部,結(jié)果存放在EAX。為何這里是”jbe”指令?switch-case語句舉例intsw_test(inta,intb,intc){intresult;switch(a){case15:c=b&0x0f;
case10:result=c+50;break;case12:
case17:result=b+50;break;case14:result=bbreak;default:result=a;}returnresult;}
跳轉(zhuǎn)表在目標(biāo)文件的只讀節(jié)中,按4字節(jié)邊界對齊。R[eax]=a-10=iif(a-10)>7轉(zhuǎn)L5轉(zhuǎn).L8+4*i
處的地址1011121314151617a=a在10和17之間循環(huán)結(jié)構(gòu)的機器級表示do~while循環(huán)的機器級表示doloop_body_statement
while(cond_expr);loop:
loop_body_statementc=cond_expr;
if(c)gotoloop;while(cond_expr)loop_body_statement
c=cond_expr;
if(!c)gotodone;loop:
loop_body_statementc=cond_expr;
if(c)gotoloop;done:for(begin_expr;cond_expr;update_expr) loop_body_statementwhile循環(huán)的機器級表示
for循環(huán)的機器級表示
begin_expr;c=cond_expr;
if(!c)gotodone;loop:
loop_body_statement
update_expr;c=cond_expr;
if(c)gotoloop;done:紅色處為條件轉(zhuǎn)移指令!循環(huán)結(jié)構(gòu)與遞歸的比較
遞歸函數(shù)nn_sum僅為說明原理,實際上可直接用公式,為說明循環(huán)的機器級表示,這里用循環(huán)實現(xiàn)。
intnn_sum(intn){ inti; intresult=0; for(i=1;i<=n;i++) result+=i; returnresult;}
movl8(%ebp),%ecxmovl$0,%eaxmovl$1,%edxcmpl%ecx,%edxjg.L2.L1:addl%edx,%eaxaddl$1,%edxcmpl%ecx,%edxjle.L1.L2過程體中沒用到被調(diào)用過程保存寄存器。因而,該過程棧幀中僅需保留EBP,即其棧幀僅占用4字節(jié)空間,而遞歸方式則占用了(16n+12)字節(jié)??臻g,多用了(16n+8)字節(jié),每次遞歸調(diào)用都要執(zhí)行16條指令,一共多了n次過程調(diào)用,因而,遞歸方式比循環(huán)方式至少多執(zhí)行了16n條指令。由此可以看出,為了提高程序的性能,若能用非遞歸方式執(zhí)行則最好用非遞歸方式。
局部變量i和result被分別分配在EDX和EAX中。通常復(fù)雜局部變量被分配在棧中,而這里都是簡單變量SKIP遞歸過程調(diào)用舉例intnn_sum(intn){ intresult; if(n<=0) result=0; else result=n+nn_sum(n-1); returnresult;}PSum(n)Sum(
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024版指標(biāo)房屋銷售協(xié)議條款版
- 二手房交易中介協(xié)議合同范本(2024版)
- 2025年度銷售業(yè)務(wù)員兼職崗位員工激勵與績效改進合同2篇
- 二零二五年度別墅景觀綠化養(yǎng)護合同3篇
- 二零二五版國際會展中心物業(yè)全面服務(wù)與管理協(xié)議3篇
- 專業(yè)廣告代理服務(wù)協(xié)議(2024版)版A版
- 2024項目合作中間人傭金協(xié)議書
- 二零二五年度雞苗運輸時間優(yōu)化及效率提升合同3篇
- 二零二五版?zhèn)€人汽車銷售代理合同模板3篇
- 二零二五年度二手汽車租賃與環(huán)保節(jié)能服務(wù)合同3篇
- 高處作業(yè)安全培訓(xùn)課件-
- 職中英語期末考試質(zhì)量分析
- 中國的世界遺產(chǎn)智慧樹知到答案章節(jié)測試2023年遼寧科技大學(xué)
- 急性腹瀉與慢性腹瀉修改版
- 先天性肌性斜頸的康復(fù)
- 《國際市場營銷》案例
- GB/T 37518-2019代理報關(guān)服務(wù)規(guī)范
- GB/T 156-2017標(biāo)準(zhǔn)電壓
- PPT溝通的藝術(shù)課件
- 內(nèi)科學(xué):巨幼細胞性貧血課件
- 暑假家校聯(lián)系情況記錄表
評論
0/150
提交評論