版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第三章程序的轉(zhuǎn)換及機(jī)器級(jí)表示
程序轉(zhuǎn)換概述
IA-32指令系統(tǒng)
C語(yǔ)言程序的機(jī)器級(jí)表示
復(fù)雜數(shù)據(jù)類型的分配和訪問(wèn)
x86-64架構(gòu)程序的轉(zhuǎn)換與機(jī)器級(jí)表示主要教學(xué)目標(biāo)了解高級(jí)語(yǔ)言與匯編語(yǔ)言、匯編語(yǔ)言與機(jī)器語(yǔ)言之間的關(guān)系掌握有關(guān)指令格式、操作數(shù)類型、尋址方式、操作類型等內(nèi)容了解高級(jí)語(yǔ)言源程序中的語(yǔ)句與機(jī)器級(jí)代碼之間的對(duì)應(yīng)關(guān)系了解復(fù)雜數(shù)據(jù)類型(數(shù)組、結(jié)構(gòu)等)的機(jī)器級(jí)實(shí)現(xiàn)主要教學(xué)內(nèi)容介紹C語(yǔ)言程序與IA-32機(jī)器級(jí)指令之間的對(duì)應(yīng)關(guān)系。主要包括:程序轉(zhuǎn)換概述、IA-32指令系統(tǒng)、C語(yǔ)言中控制語(yǔ)句和過(guò)程調(diào)用等機(jī)器級(jí)實(shí)現(xiàn)、復(fù)雜數(shù)據(jù)類型(數(shù)組、結(jié)構(gòu)等)的機(jī)器級(jí)實(shí)現(xiàn)等。本章所用的機(jī)器級(jí)表示主要以匯編語(yǔ)言形式表示為主。采用逆向工程方法!程序的機(jī)器級(jí)表示分以下五個(gè)部分介紹第一講:程序轉(zhuǎn)換概述機(jī)器指令和匯編指令機(jī)器級(jí)程序員感覺(jué)到的屬性和功能特性高級(jí)語(yǔ)言程序轉(zhuǎn)換為機(jī)器代碼的過(guò)程第二講:IA-32指令系統(tǒng)第三講:C語(yǔ)言程序的機(jī)器級(jí)表示過(guò)程調(diào)用的機(jī)器級(jí)表示選擇語(yǔ)句的機(jī)器級(jí)表示循環(huán)結(jié)構(gòu)的機(jī)器級(jí)表示第四講:復(fù)雜數(shù)據(jù)類型的分配和訪問(wèn)數(shù)組的分配和訪問(wèn)結(jié)構(gòu)體數(shù)據(jù)的分配和訪問(wèn)聯(lián)合體數(shù)據(jù)的分配和訪問(wèn)數(shù)據(jù)的對(duì)齊第五講:x86-64指令系統(tǒng)從高級(jí)語(yǔ)言程序出發(fā),用其對(duì)應(yīng)的機(jī)器級(jí)代碼以及內(nèi)存(棧)中信息的變化來(lái)說(shuō)明底層實(shí)現(xiàn)圍繞C語(yǔ)言中的語(yǔ)句和復(fù)雜數(shù)據(jù)類型,解釋其在底層機(jī)器級(jí)的實(shí)現(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軟件硬件匯編指令機(jī)器指令…11111001011…微指令swap0($2),4($2)偽指令“指令”的概念計(jì)算機(jī)中有微指令、機(jī)器指令和偽(宏)指令之分微指令是微程序級(jí)命令,屬于硬件范疇偽指令是由若干機(jī)器指令組成的指令序列,屬于軟件范疇機(jī)器指令介于二者之間,處于硬件和軟件的交界面本章中提及的指令都指機(jī)器指令匯編指令是機(jī)器指令的匯編表示形式,即符號(hào)表示機(jī)器指令和匯編指令一一對(duì)應(yīng),它們都與具體機(jī)器結(jié)構(gòu)有關(guān),都屬于機(jī)器級(jí)指令
機(jī)器級(jí)指令機(jī)器指令和匯編指令一一對(duì)應(yīng),都是機(jī)器級(jí)指令機(jī)器指令是一個(gè)0/1序列,由若干字段組成匯編指令是機(jī)器指令的符號(hào)表示(可能有不同的格式)mov、movb、bx、%bx等都是助記符指令的功能為:M[R[bx]+R[di]-6]←R[cl]
操作碼尋址方式寄存器編號(hào)立即數(shù)(位移量)mov[bx+di-6],clmovb%cl,-6(%bx,%di)或Intel格式AT&T格式補(bǔ)碼11111010的真值為多少?寄存器傳送語(yǔ)言RTL(RegisterTransferLanguage)
R:寄存器內(nèi)容M:存儲(chǔ)單元內(nèi)容
本課程采用AT&T格式操作碼:opcode;w:與機(jī)器模式(16/32位)一起確定寄存器位數(shù)(AL/AX/EAX);d:操作方向?qū)ぶ贩绞剑簃od、r/m、reg/op三個(gè)字段與w字段和機(jī)器模式一起確定操作數(shù)所在的寄存器編號(hào)或有效地址計(jì)算方式SIB中基址B和變址I都可是8個(gè)GRS中任一個(gè);SS給出比例因子位移量和立即數(shù)的長(zhǎng)度可以是:1B(8位)、2B(16位)、4B(32位)IA-32機(jī)器指令格式回顧:計(jì)算機(jī)中數(shù)據(jù)的存儲(chǔ)計(jì)算機(jī)中的數(shù)據(jù)存放在哪里?寄存器文件通用寄存器組GPRs存儲(chǔ)器指令中需給出的信息:操作性質(zhì)(操作碼)源操作數(shù)1或/和源操作數(shù)2
(立即數(shù)、寄存器編號(hào)、存儲(chǔ)地址)目的操作數(shù)地址(寄存器編號(hào)、存儲(chǔ)地址)存儲(chǔ)地址的描述與操作數(shù)的數(shù)據(jù)結(jié)構(gòu)有關(guān)!相當(dāng)于宿舍書(shū)架相當(dāng)于圖書(shū)館書(shū)架I/OCPUCompilerOperatingSystemApplicationDigitalDesignCircuitDesignInstructionSetArchitectureMMAssembler回顧:指令集體系結(jié)構(gòu)ISAISA(InstructionSetArchitecture)位于軟件和硬件之間硬件的功能通過(guò)ISA提供出來(lái)軟件通過(guò)ISA規(guī)定的”指令”使用硬件ISA規(guī)定了:可執(zhí)行的指令的集合,包括指令格式、操作種類以及每種操作對(duì)應(yīng)的操作數(shù)的相應(yīng)規(guī)定;指令可以接受的操作數(shù)的類型;操作數(shù)所能存放的寄存器組的結(jié)構(gòu),包括每個(gè)寄存器的名稱、編號(hào)、長(zhǎng)度和用途;操作數(shù)所能存放的存儲(chǔ)空間的大小和編址方式;操作數(shù)在存儲(chǔ)空間存放時(shí)按照大端還是小端方式存放;指令獲取操作數(shù)的方式,即尋址方式;指令執(zhí)行過(guò)程的控制方式,包括程序計(jì)數(shù)器、條件碼定義等。高級(jí)語(yǔ)言程序轉(zhuǎn)換為機(jī)器代碼的過(guò)程
預(yù)處理:在高級(jí)語(yǔ)言源程序中插入所有用#include命令指定的文件和用#define聲明指定的宏。編譯:將預(yù)處理后的源程序文件編譯生成相應(yīng)的匯編語(yǔ)言程序。匯編:由匯編程序?qū)R編語(yǔ)言源程序文件轉(zhuǎn)換為可重定位的機(jī)器語(yǔ)言目標(biāo)代碼文件。鏈接:由鏈接器將多個(gè)可重定位的機(jī)器語(yǔ)言目標(biāo)文件以及庫(kù)例程(如printf()庫(kù)函數(shù))鏈接起來(lái),生成最終的可執(zhí)行目標(biāo)文件。用GCC編譯器套件進(jìn)行轉(zhuǎn)換的過(guò)程GCC使用舉例兩個(gè)源程序文件test1.c和test2.c,最終生成可執(zhí)行文件為testgcc-O1test1.ctest2.c-otest選項(xiàng)-O1表示一級(jí)優(yōu)化,-O2為二級(jí)優(yōu)化,選項(xiàng)-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位移量機(jī)器指令匯編指令編譯得到的與反匯編得到的匯編指令形式稍有差異“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開(kāi)始,test中的代碼從80483d4開(kāi)始!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í)行文件的存儲(chǔ)器映像0ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫(kù)區(qū)域堆(heap)(由malloc動(dòng)態(tài)生成)用戶棧(Userstack)動(dòng)態(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
從高地址向低地址增長(zhǎng)!程序的機(jī)器級(jí)表示分以下五個(gè)部分介紹第一講:程序轉(zhuǎn)換概述機(jī)器指令和匯編指令機(jī)器級(jí)程序員感覺(jué)到的屬性和功能特性高級(jí)語(yǔ)言程序轉(zhuǎn)換為機(jī)器代碼的過(guò)程第二講:IA-32指令系統(tǒng)第三講:C語(yǔ)言程序的機(jī)器級(jí)表示過(guò)程調(diào)用的機(jī)器級(jí)表示選擇語(yǔ)句的機(jī)器級(jí)表示循環(huán)結(jié)構(gòu)的機(jī)器級(jí)表示第四講:復(fù)雜數(shù)據(jù)類型的分配和訪問(wèn)數(shù)組的分配和訪問(wèn)結(jié)構(gòu)體數(shù)據(jù)的分配和訪問(wèn)聯(lián)合體數(shù)據(jù)的分配和訪問(wèn)數(shù)據(jù)的對(duì)齊第五講:x86-64指令系統(tǒng)從高級(jí)語(yǔ)言程序出發(fā),用其對(duì)應(yīng)的機(jī)器級(jí)代碼以及內(nèi)存(棧)中信息的變化來(lái)說(shuō)明底層實(shí)現(xiàn)圍繞C語(yǔ)言中的語(yǔ)句和復(fù)雜數(shù)據(jù)類型,解釋其在底層機(jī)器級(jí)的實(shí)現(xiàn)方法IA-32/x64指令系統(tǒng)概述x86是Intel開(kāi)發(fā)的一類處理器體系結(jié)構(gòu)的泛稱包括Intel8086、80286、i386和i486等,因此其架構(gòu)被稱為“x86”由于數(shù)字并不能作為注冊(cè)商標(biāo),因此,后來(lái)使用了可注冊(cè)的名稱,如Pentium、PentiumPro、Core2、Corei7等現(xiàn)在Intel把32位x86架構(gòu)的名稱x86-32改稱為IA-32由AMD首先提出了一個(gè)兼容IA-32指令集的64位版本擴(kuò)充了指令及寄存器長(zhǎng)度和個(gè)數(shù)等,更新了參數(shù)傳送方式AMD稱其為AMD64,Intel稱其為Intl64(不同于IA-64)命名為“x86-64”,有時(shí)也簡(jiǎn)稱為x64本課程主要介紹IA-32,最后簡(jiǎn)要介紹x-64回顧:計(jì)算機(jī)系統(tǒng)核心層之間的關(guān)聯(lián)前端遵循語(yǔ)言規(guī)范高級(jí)語(yǔ)言程序詞法、語(yǔ)法及語(yǔ)義分析中間代碼生成中間代碼目標(biāo)代碼生成及優(yōu)化目標(biāo)代碼后端遵循ISA規(guī)范和ABI規(guī)范后端根據(jù)ISA規(guī)范和應(yīng)用程序二進(jìn)制接口(ApplicationBinaryInterface,ABI)規(guī)范進(jìn)行設(shè)計(jì)實(shí)現(xiàn)。ABI是為運(yùn)行在特定ISA及特定操作系統(tǒng)之上的應(yīng)用程序規(guī)定的一種機(jī)器級(jí)目標(biāo)代碼層接口描述了應(yīng)用程序和操作系統(tǒng)之間、應(yīng)用程序和所調(diào)用的庫(kù)之間、不同組成部分(如過(guò)程或函數(shù))之間在較低層次上的機(jī)器級(jí)代碼接口。運(yùn)行平臺(tái):操作系統(tǒng)+ISA架構(gòu)本課程所用平臺(tái)為IA-32/x86-64+Linux+GCC+C語(yǔ)言,Linux操作系統(tǒng)下一般使用systemVABI同一個(gè)C語(yǔ)言源程序,使用遵循不同ABI規(guī)范的編譯器進(jìn)行編譯,其執(zhí)行結(jié)果可能不一樣。程序員將程序移植到另一個(gè)系統(tǒng)時(shí),一定要仔細(xì)閱讀目標(biāo)系統(tǒng)的ABI規(guī)范。I386SystemVABI規(guī)定的數(shù)據(jù)類型IA-32的寄存器組織8個(gè)通用寄存器兩個(gè)專用寄存器6個(gè)段寄存器IA-32的標(biāo)志寄存器EFLAGS6個(gè)條件標(biāo)志OF、SF、ZF、CF各是什么標(biāo)志(條件碼)?AF:輔助進(jìn)位標(biāo)志(BCD碼運(yùn)算時(shí)才有意義)PF:奇偶標(biāo)志3個(gè)控制標(biāo)志DF(DirectionFlag):方向標(biāo)志(自動(dòng)變址方向是增還是減)IF(InterruptFlag):中斷允許標(biāo)志(僅對(duì)外部可屏蔽中斷有用)TF(TrapFlag):陷阱標(biāo)志(是否是單步跟蹤狀態(tài))……808680286/386X87浮點(diǎn)指令、MMX和SSE指令I(lǐng)A-32的浮點(diǎn)處理架構(gòu)有兩種:浮點(diǎn)協(xié)處理器x87架構(gòu)(x87FPU)8個(gè)80位寄存器ST(0)~ST(7)(采用棧結(jié)構(gòu)),棧頂為ST(0)由MMX發(fā)展而來(lái)的SSE架構(gòu)MMX指令使用8個(gè)64位寄存器MM0~MM7,借用8個(gè)80位寄存器ST(0)~ST(7)中64位尾數(shù)所占的位,可同時(shí)處理8個(gè)字節(jié),或4個(gè)字,或2個(gè)雙字,或一個(gè)64位的數(shù)據(jù)MMX指令并沒(méi)帶來(lái)3D游戲性能的顯著提升,故相繼推出SSE指令集,它們都采用SIMD(單指令多數(shù)據(jù),也稱數(shù)據(jù)級(jí)并行)技術(shù)SSE指令集將80位浮點(diǎn)寄存器擴(kuò)充到128位多媒體擴(kuò)展通用寄存器XMM0~XMM7,可同時(shí)處理16個(gè)字節(jié),或8個(gè)字,或4個(gè)雙字(32位整數(shù)或單精度浮點(diǎn)數(shù)),或兩個(gè)四字的數(shù)據(jù),而且從SSE2開(kāi)始,還支持128位整數(shù)運(yùn)算或同時(shí)并行處理兩個(gè)64位雙精度浮點(diǎn)數(shù)IA-32中通用寄存器中的編號(hào)反映了體系結(jié)構(gòu)發(fā)展的軌跡,字長(zhǎng)不斷擴(kuò)充,指令保持兼容ST(0)~ST(7)是80位,MM0~MM7使用其低64位IA-32的尋址方式尋址方式根據(jù)指令給定信息得到操作數(shù)或操作數(shù)地址操作數(shù)所在的位置指令中:立即尋址寄存器中:寄存器尋址存儲(chǔ)單元中(屬于存儲(chǔ)器操作數(shù),按字節(jié)編址):其他尋址方式存儲(chǔ)器操作數(shù)的尋址方式與微處理器的工作模式有關(guān)兩種工作模式:實(shí)地址模式和保護(hù)模式實(shí)地址模式(基本用不到)為與8086/8088兼容而設(shè),加電或復(fù)位時(shí)尋址空間為1MB,20位地址:(CS)<<4+(IP)保護(hù)模式(需要掌握)加電后進(jìn)入,采用虛擬存儲(chǔ)管理,多任務(wù)情況下隔離、保護(hù)80286以上高檔微處理器最常用的工作模式尋址空間為232B,32位地址分段(段基址+段內(nèi)偏移量)保護(hù)模式下的尋址方式SR段寄存器(間接)確定操作數(shù)所在段的段基址有效地址給出操作數(shù)在所在段的偏移地址尋址過(guò)程涉及到“分段虛擬管理方式”,將在第6章討論存儲(chǔ)器操作數(shù)跳轉(zhuǎn)目標(biāo)指令地址存儲(chǔ)器操作數(shù)的尋址方式intx;floata[100];shortb[4][4];charc;doubled[10];a[i]的地址如何計(jì)算?104+i×4i=99時(shí),104+99×4=500b[i][j]的地址如何計(jì)算?504+i×8+j×2i=3、j=2時(shí),504+24+4=532d[i]的地址如何計(jì)算?544+i×8i=9時(shí),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存儲(chǔ)器操作數(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:符號(hào)擴(kuò)展傳送,如movsbw、movswl等MOVZ:零擴(kuò)展傳送,如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)是一種采用“先進(jìn)后出”方式進(jìn)行訪問(wèn)的一塊存儲(chǔ)區(qū),用于嵌套過(guò)程調(diào)用。從高地址向低地址增長(zhǎng)“棧”不等于“堆?!保ㄓ伞岸选焙汀皸!苯M成)棧底棧底R(shí)[sp]←R[sp]-2、M[R[sp]]←R[ax]R[ax]←M[R[sp]]、[sp]←R[sp]+2為什么AL在棧頂?小端方式!傳送指令舉例將以下Intel格式指令轉(zhuǎn)換為AT&T格式指令,并說(shuō)明功能。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)定點(diǎn)算術(shù)運(yùn)算指令加/減運(yùn)算(影響標(biāo)志、不區(qū)分無(wú)/帶符號(hào))ADD:加,包括addb、addw、addl等SUB:減,包括subb、subw、subl等增1/減1運(yùn)算(影響除CF以外的標(biāo)志、不區(qū)分無(wú)/帶符號(hào))INC:加,包括incb、incw、incl等DEC:減,包括decb、decw、decl等取負(fù)運(yùn)算(影響標(biāo)志、若對(duì)0取負(fù),則結(jié)果為0且CF=0,否則CF=1)NEG:取負(fù),包括negb、negw、negl等比較運(yùn)算(做減法得到標(biāo)志、不區(qū)分無(wú)/帶符號(hào))CMP:比較,包括cmpb、cmpw、cmpl等乘/除運(yùn)算(區(qū)分無(wú)/帶符號(hào))MUL/IMUL:無(wú)符號(hào)乘/帶符號(hào)乘(影響標(biāo)志OF和CF)DIV/IDIV:帶無(wú)符號(hào)除/帶符號(hào)除整數(shù)乘除指令乘法指令:可給出一個(gè)、兩個(gè)或三個(gè)操作數(shù)若給出一個(gè)操作數(shù)SRC,則另一個(gè)源操作數(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位若指令中給出兩個(gè)操作數(shù)DST和SRC,則將DST和SRC相乘,結(jié)果在DST中。n位×n位=n位若指令中給出三個(gè)操作數(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í)能查閱到并理解即可。定點(diǎn)算術(shù)運(yùn)算指令匯總定點(diǎn)加法指令舉例假設(shè)R[ax]=FFFAH,R[bx]=FFF0H,則執(zhí)行以下指令后
“addw%bx,%ax”
AX、BX中的內(nèi)容各是什么?標(biāo)志CF、OF、ZF、SF各是什么?要求分別將操作數(shù)作為無(wú)符號(hào)數(shù)和帶符號(hào)整數(shù)解釋并驗(yàn)證指令執(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
若是無(wú)符號(hào)整數(shù)運(yùn)算,則CF=1說(shuō)明結(jié)果溢出驗(yàn)證:FFFA的真值為65535-5=65530,F(xiàn)FF0的真值為65520FFEA的真值為65535-21=65514≠65530+65520,即溢出
若是帶符號(hào)整數(shù)運(yùn)算,則OF=0說(shuō)明結(jié)果沒(méi)有溢出驗(yàn)證:FFFA的真值為-6,F(xiàn)FF0的真值為-16FFEA的真值為-22=-6+(-16),結(jié)果正確,無(wú)溢出定點(diǎn)乘法指令舉例假設(shè)R[eax]=000000B4H,R[ebx]=00000011H,M[000000F8H]=000000A0H,請(qǐng)問(wèn):(1)執(zhí)行指令“mulb%bl”后,哪些寄存器的內(nèi)容會(huì)發(fā)生變化?是否與執(zhí)行“imulb%bl”指令所發(fā)生的變化一樣?為什么?請(qǐng)用該例給出的數(shù)據(jù)驗(yàn)證你的結(jié)論。解:“mulb%bl”功能為R[ax]←R[al]×R[bl],執(zhí)行結(jié)果如下R[ax]=B4H×11H(無(wú)符號(hào)整數(shù)180和17相乘)
R[ax]=0BF4H,真值為3060=180×17
“imulb%bl”功能為R[ax]←R[al]×R[bl]R[ax]=B4H×11H(帶符號(hào)整數(shù)-76和17相乘)若R[ax]=0BF4H,則真值為3060≠-76×17 R[al]=F4H,R[ah]=?AH中的值不一樣!R[ax]=FAF4H,真值為-1292=-76×171011010000010001x10110100101101000000101111110100AL=?AH=?對(duì)于帶符號(hào)乘,若積只取低n位,則和無(wú)符號(hào)相同;若取2n位,則采用“布斯”乘法無(wú)符號(hào)乘:定點(diǎn)乘法指令舉例布斯乘法:10110100001-1001-1000100010x0000000001001100111111110110100000001001100111101101001111101011110100AL=?AH=?R[ax]=FAF4H,真值為-1292=-76×17R[ax]=B4H×11H“imulb%bl”定點(diǎn)乘法指令舉例假設(shè)R[eax]=000000B4H,R[ebx]=00000011H,M[000000F8H]=000000A0H,請(qǐng)問(wèn):(2)執(zhí)行指令“imull$-16,(%eax,%ebx,4),%eax”后哪些寄存器和存儲(chǔ)單元發(fā)生了變化?乘積的機(jī)器數(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(帶符號(hào)整數(shù)乘)=FFFFFF60H<<4 =FFFFF600HEAX中的真值為-2560SKIP整數(shù)乘除指令乘法指令:可給出一個(gè)、兩個(gè)或三個(gè)操作數(shù)若給出一個(gè)操作數(shù)SRC,則另一個(gè)源操作數(shù)隱含在AL/AX/EAX中,將SRC和累加器內(nèi)容相乘,結(jié)果存放在AX(16位)或DX-AX(32位)或EDX-EAX(64位)中。DX-AX表示32位乘積的高、低16位分別在DX和AX中。若指令中給出兩個(gè)操作數(shù)DST和SRC,則將DST和SRC相乘,結(jié)果在DST中。若指令中給出三個(gè)操作數(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)容不要死記硬背,遇到具體指令時(shí)能查閱到并理解即可。BACKBACKIA-32常用指令類型(3)按位運(yùn)算指令邏輯運(yùn)算(僅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:做“與”操作測(cè)試,僅影響標(biāo)志移位運(yùn)算(左/右移時(shí),最高/最低位送CF)SHL/SHR:邏輯左/右移,包括shlb、shrw、shrl等SAL/SAR:算術(shù)左/右移,左移判溢出,右移高位補(bǔ)符(移位前、后符號(hào)位發(fā)生變化,則OF=1)ROL/ROR:循環(huán)左/右移,包括rolb、rorw、roll等RCL/RCR:帶循環(huán)左/右移,將CF作為操作數(shù)一部分循環(huán)移位以上內(nèi)容不要死記硬背,遇到具體指令時(shí)能查閱到并理解即可。按位運(yùn)算指令舉例假設(shè)short型變量x被編譯器分配在寄存器AX中,R[ax]=FF80H,則以下匯編代碼段執(zhí)行后變量x的機(jī)器數(shù)和真值分別是多少?
movw%ax,%dxsalw$2,%axaddl%dx,%axsarw$1,%ax解:$2和$1分別表示立即數(shù)2和1。
x是short型變量,故都是算術(shù)移位指令,并進(jìn)行帶符號(hào)整數(shù)加。假設(shè)上述代碼段執(zhí)行前R[ax]=x,則執(zhí)行((x<<2)+x)>>1后,R[ax]=5x/2。算術(shù)左移時(shí),AX中的內(nèi)容在移位前、后符號(hào)未發(fā)生變化,故OF=0,沒(méi)有溢出。最終AX的內(nèi)容為FEC0H,解釋為short型整數(shù)時(shí),其值為-320。驗(yàn)證:x=-128,5x/2=-320。經(jīng)驗(yàn)證,結(jié)果正確。1111111110000000<<21111111110000000+11111110000000001111110110000000>>1=1111111011000000逆向工程:從匯編指令退出高級(jí)語(yǔ)言程序代碼移位指令舉例算術(shù)邏輯IA-32常用指令類型(4)控制轉(zhuǎn)移指令
指令執(zhí)行可按順序或跳轉(zhuǎn)到轉(zhuǎn)移目標(biāo)指令處執(zhí)行無(wú)條件轉(zhuǎn)移指令JMPDST:無(wú)條件轉(zhuǎn)移到目標(biāo)指令DST處執(zhí)行條件轉(zhuǎn)移JccDST:cc為條件碼,根據(jù)標(biāo)志(條件碼)判斷是否滿足條件,若滿足,則轉(zhuǎn)移到目標(biāo)指令DST處執(zhí)行,否則按順序執(zhí)行條件設(shè)置SETccDST:將條件碼cc保存到DST(通常是一個(gè)8位寄存器)調(diào)用和返回指令
(用于過(guò)程調(diào)用)CALLDST:返回地址RA入棧,轉(zhuǎn)DST處執(zhí)行RET:從棧中取出返回地址RA,轉(zhuǎn)到RA處執(zhí)行中斷指令
(詳見(jiàn)第7、8章)以上內(nèi)容不要死記硬背,遇到具體指令時(shí)能查閱到并理解即可。條件轉(zhuǎn)移指令分三類:(1)根據(jù)單個(gè)標(biāo)志的值轉(zhuǎn)移(2)按無(wú)符號(hào)整數(shù)比較轉(zhuǎn)移(3)按帶符號(hào)整數(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時(shí),大于Signed:OF=SF時(shí),大于OF=1、ZF=0SF=0、借位CF=0+1101101001111010OF=1、ZF=0SF=1、借位CF=1例子:C表達(dá)式類型轉(zhuǎn)換順序unsignedlonglong↑longlong↑unsigned↑
int↑(unsigned)char,short條件設(shè)置指令SETccDST:將條件碼cc保存到DST(通常是一個(gè)8位寄存器)猜測(cè):各用哪種條件設(shè)置指令?charc=-1;d=(a>c)?1:0unsignedshortb=1;unsignedinta=1;d=(b>c)?1:0無(wú)符號(hào)帶符號(hào)例子:程序的機(jī)器級(jí)表示與執(zhí)行intsum(inta[],unsignedlen){inti,sum=0;for(i=0;i<=len–1;i++) sum+=a[i];returnsum;}當(dāng)參數(shù)len為0時(shí),返回值應(yīng)該是0,但是在機(jī)器上執(zhí)行時(shí),卻發(fā)生了存儲(chǔ)器訪問(wèn)異常。
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分別存放在哪個(gè)寄存器中?%eax?%edx?subl$1,%edx指令的執(zhí)行結(jié)果“subl$1,%edx”執(zhí)行時(shí):A=00000000H,B為00000001H,Sub=1,因此Result是32個(gè)1。Result加法器nnnAZFCiConBn01多路選擇器SubBOF加/減運(yùn)算部件CF=CoSubSF當(dāng)Sub為1時(shí),做減法當(dāng)Sub為0時(shí),做加法已知EDX中為len=00000000Hcpml%edx,%eax指令的執(zhí)行結(jié)果“cmpl%edx,%eax”執(zhí)行時(shí):A=00000000H,B為FFFFFFFFH,Sub=1,因此Result是0…01,CF=1,ZF=0,OF=0,SF=0
Result加法器nnnAZFCiConBn01多路選擇器SubBOF加/減運(yùn)算部件CF=CoSubSF當(dāng)Sub為1時(shí),做減法當(dāng)Sub為0時(shí),做加法已知EDX中為len-1=FFFFFFFFH
EAX中為i=00000000Hjbe.L3指令的執(zhí)行結(jié)果指令轉(zhuǎn)移條件說(shuō)明JA/JNBElabelCF=0ANDZF=0無(wú)符號(hào)數(shù)A>BJAE/JNBlabelCF=0ORZF=1無(wú)符號(hào)數(shù)A≥BJB/JNAElabelCF=1ANDZF=0無(wú)符號(hào)數(shù)A<BJBE/JNAlabelCF=1ORZF=1無(wú)符號(hào)數(shù)A≤BJG/JNLElabelSF=OFANDZF=0有符號(hào)數(shù)A>BJGE/JNLlabelSF=OFORZF=1有符號(hào)數(shù)A≥BJL/JNGElabelSF≠OFANDZF=0有符號(hào)數(shù)A<BJLE/JNGlabelSF≠OFORZF=1有符號(hào)數(shù)A≤B“cmpl%edx,%eax”執(zhí)行結(jié)果是
CF=1,ZF=0,OF=0,SF=0,說(shuō)明滿足條件,應(yīng)轉(zhuǎn)移到.L3執(zhí)行!顯然,對(duì)于每個(gè)i都滿足條件,因?yàn)槿魏螣o(wú)符號(hào)數(shù)都比32個(gè)1小,因此循環(huán)體被不斷執(zhí)行,最終導(dǎo)致數(shù)組訪問(wèn)越界而發(fā)生存儲(chǔ)器訪問(wèn)異常。例子:程序的機(jī)器級(jí)表示與執(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分別存放在哪個(gè)寄存器中?%eax?%edx?jle.L3指令的執(zhí)行結(jié)果指令轉(zhuǎn)移條件說(shuō)明JA/JNBElabelCF=0ANDZF=0無(wú)符號(hào)數(shù)A>BJAE/JNBlabelCF=0ORZF=1無(wú)符號(hào)數(shù)A≥BJB/JNAElabelCF=1ANDZF=0無(wú)符號(hào)數(shù)A<BJBE/JNAlabelCF=1ORZF=1無(wú)符號(hào)數(shù)A≤BJG/JNLElabelSF=OFANDZF=0有符號(hào)數(shù)A>BJGE/JNLlabelSF=OFORZF=1有符號(hào)數(shù)A≥BJL/JNGElabelSF≠OFANDZF=0有符號(hào)數(shù)A<BJLE/JNGlabelSF≠OFORZF=1有符號(hào)數(shù)A≤B“cmpl%edx,%eax”執(zhí)行結(jié)果是CF=1,ZF=0,OF=0,SF=0,
說(shuō)明不滿足條件,應(yīng)跳出循環(huán)執(zhí)行,執(zhí)行結(jié)果正常。第一、二講總結(jié)高級(jí)語(yǔ)言程序總是轉(zhuǎn)換為機(jī)器代碼才能在機(jī)器上執(zhí)行轉(zhuǎn)換過(guò)程:預(yù)處理、編譯、匯編、鏈接機(jī)器代碼是二進(jìn)制代碼,可DUMP為匯編代碼表示ISA規(guī)定了一臺(tái)機(jī)器的指令系統(tǒng)涉及到的所有方面,例如:所有指令的指令格式、功能通用寄存器的個(gè)數(shù)、位數(shù)、編號(hào)和功能存儲(chǔ)地址空間大小、編址方式、大/小端指令尋址方式IA-32是典型的CISC(復(fù)雜指令集計(jì)算機(jī))風(fēng)格ISAIntel格式匯編、AT&T格式匯編(本課程使用)指令類型(傳送、算術(shù)、位操作、控制、浮點(diǎn)、…)尋址方式立即、寄存器、存儲(chǔ)器(SR:[B]+[I]*s+A)程序的機(jī)器級(jí)表示分以下五個(gè)部分介紹第一講:程序轉(zhuǎn)換概述機(jī)器指令和匯編指令機(jī)器級(jí)程序員感覺(jué)到的屬性和功能特性高級(jí)語(yǔ)言程序轉(zhuǎn)換為機(jī)器代碼的過(guò)程第二講:IA-32指令系統(tǒng)第三講:C語(yǔ)言程序的機(jī)器級(jí)表示過(guò)程調(diào)用的機(jī)器級(jí)表示選擇語(yǔ)句的機(jī)器級(jí)表示循環(huán)結(jié)構(gòu)的機(jī)器級(jí)表示第四講:復(fù)雜數(shù)據(jù)類型的分配和訪問(wèn)數(shù)組的分配和訪問(wèn)結(jié)構(gòu)體數(shù)據(jù)的分配和訪問(wèn)聯(lián)合體數(shù)據(jù)的分配和訪問(wèn)數(shù)據(jù)的對(duì)齊第五講:x86-64指令系統(tǒng)從高級(jí)語(yǔ)言程序出發(fā),用其對(duì)應(yīng)的機(jī)器級(jí)代碼以及內(nèi)存(棧)中信息的變化來(lái)說(shuō)明底層實(shí)現(xiàn)圍繞C語(yǔ)言中的語(yǔ)句和復(fù)雜數(shù)據(jù)類型,解釋其在底層機(jī)器級(jí)的實(shí)現(xiàn)方法intadd(intx,inty){ returnx+y;}intmain(){ int t1=125;intt2=80; int sum=add(t1,t2); returnsum;}過(guò)程調(diào)用的機(jī)器級(jí)表示以下過(guò)程(函數(shù))調(diào)用對(duì)應(yīng)的機(jī)器級(jí)代碼是什么?如何將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ī)范定義,編譯器強(qiáng)制執(zhí)行,匯編語(yǔ)言程序員也必須強(qiáng)制按照這些約定執(zhí)行,包括寄存器的使用、棧幀的建立和參數(shù)傳遞等??蓤?zhí)行文件的存儲(chǔ)器映像0ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫(kù)區(qū)域堆(heap)(由malloc動(dòng)態(tài)生成)用戶棧(Userstack)動(dòng)態(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
從高地址向低地址增長(zhǎng)!IA-32中參數(shù)通過(guò)棧來(lái)傳遞棧(stack)在哪里?過(guò)程調(diào)用的機(jī)器級(jí)表示
過(guò)程調(diào)用的執(zhí)行步驟(P為調(diào)用者,Q為被調(diào)用者)(1)P將入口參數(shù)(實(shí)參)放到Q能訪問(wèn)到的地方;(2)P保存返回地址,然后將控制轉(zhuǎn)移到Q;(3)Q保存P的現(xiàn)場(chǎng),并為自己的非靜態(tài)局部變量分配空間;(4)執(zhí)行Q的過(guò)程體(函數(shù)體);(5)Q恢復(fù)P的現(xiàn)場(chǎng),釋放局部變量空間;(6)Q取出返回地址,將控制轉(zhuǎn)移到P。結(jié)束階段準(zhǔn)備階段Q過(guò)程P過(guò)程處理階段CALL指令RET指令
main: add:存放參數(shù) 取出參數(shù)調(diào)出add執(zhí)行 執(zhí)行
存返回結(jié)果
返回main
何為現(xiàn)場(chǎng)?通用寄存器的內(nèi)容!為何要保存現(xiàn)場(chǎng)?因?yàn)樗羞^(guò)程共享一套通用寄存器想象:媽媽做菜過(guò)程中,讓你來(lái)完成其中一個(gè)工序時(shí)共用一套盤子的情況add(t1,t2)過(guò)程調(diào)用的機(jī)器級(jí)表示
i386SystemVABI規(guī)范約定調(diào)用者保存寄存器:EAX、EDX、ECX
當(dāng)過(guò)程P調(diào)用過(guò)程Q時(shí),Q可以直接使用這三個(gè)寄存器,不用將它們的值保存到棧中。如果P在從Q返回后還要用這三個(gè)寄存器的話,P應(yīng)在轉(zhuǎn)到Q之前先保存,并在從Q返回后先恢復(fù)它們的值再使用。被調(diào)用者保存寄存器:EBX、ESI、EDI
Q必須先將它們的值保存到棧中再使用它們,并在返回P之前恢復(fù)它們的值。EBP和ESP分別是幀指針寄存器和棧指針寄存器,分別用來(lái)指向當(dāng)前棧幀的底部和頂部。問(wèn)題:為減少準(zhǔn)備和結(jié)束階段的開(kāi)銷,每個(gè)過(guò)程應(yīng)先使用哪些寄存器?EAX、ECX、EDX!相當(dāng)于媽媽騰空的盤子相當(dāng)于媽媽還要用的盤子過(guò)程調(diào)用的機(jī)器級(jí)表示過(guò)程調(diào)用過(guò)程中棧和棧幀的變化(Q為被調(diào)用過(guò)程)①②③④Q(參數(shù)1,…,參數(shù)n);Linux可執(zhí)行文件的存儲(chǔ)映像0ESP(棧頂)brk0xC000000000x08048000內(nèi)核虛存區(qū)共享庫(kù)區(qū)域堆(heap)(由malloc動(dòng)態(tài)生成)用戶棧(Userstack)動(dòng)態(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
從高地址向低地址增長(zhǎng)!一個(gè)簡(jiǎn)單的過(guò)程調(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ù)開(kāi)始是什么?pushl%ebpmovl%esp,%ebpmovl %ebp,%esppopl %ebp
addcaller
P過(guò)程(函數(shù))的結(jié)構(gòu)一個(gè)C過(guò)程的大致結(jié)構(gòu)如下:準(zhǔn)備階段形成幀底:push指令和mov指令生成棧幀(如果需要的話):sub指令或and指令保存現(xiàn)場(chǎng)(如果有被調(diào)用者保存寄存器):push指令過(guò)程(函數(shù))體分配局部變量空間,并賦值具體處理邏輯,如果遇到函數(shù)調(diào)用時(shí)準(zhǔn)備參數(shù):將實(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個(gè)字節(jié)故在被調(diào)用函數(shù)中,使用R[ebp]+8、R[ebp]+12、R[ebp]+16作為有效地址來(lái)訪問(wèn)函數(shù)的入口參數(shù)每個(gè)過(guò)程開(kāi)始兩條指令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é)對(duì)齊過(guò)程調(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é)果?為什么?過(guò)程調(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進(jìn)行了交換過(guò)程調(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沒(méi)有交換,交換的僅是入口參數(shù)過(guò)程調(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的過(guò)程為P,P中給出形參a和y的實(shí)參分別是100和200,畫(huà)出相應(yīng)棧幀中的狀態(tài),并回答下列問(wèn)題。(1)test的形參是按值傳遞還是按地址傳遞?test的形參ptr對(duì)應(yīng)的實(shí)參是一個(gè)什么類型的值?(2)test中被改變的*ptr的結(jié)果如何返回給它的調(diào)用過(guò)程caller?(3)caller中被改變的y的結(jié)果能否返回給過(guò)程P?為什么?
testcallerP
caller執(zhí)行過(guò)程中,在進(jìn)入test之前一刻棧中的狀態(tài)如何?進(jìn)入test并生成其棧幀后,棧中狀態(tài)如何?&y:&a:Pcaller100200300前者按值、后者按地址。一定是一個(gè)地址第10行執(zhí)行后,P幀中200變成300,test退幀后,caller中通過(guò)y引用該值300第11行執(zhí)行后caller退幀并返回P,因P中無(wú)變量與之對(duì)應(yīng),故無(wú)法引用該值300若returnx+y;則函數(shù)返回400intnn_sum(intn){ intresult; if(n<=0) result=0; else result=n+nn_sum(n-1); returnresult;}遞歸過(guò)程調(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)用都會(huì)增加一個(gè)棧幀(該例為16B),所以空間開(kāi)銷很大。當(dāng)n很大時(shí)會(huì)發(fā)生棧溢出!P操作系統(tǒng)為程序分配的棧會(huì)有默認(rèn)的大小限制過(guò)程調(diào)用的機(jī)器級(jí)表示遞歸函數(shù)nn_sum的執(zhí)行流程為支持過(guò)程調(diào)用,每個(gè)過(guò)程包含準(zhǔn)備階段和結(jié)束階段。因而每增加一次過(guò)程調(diào)用,就要增加許多條包含在準(zhǔn)備階段和結(jié)束階段的額外指令,它們對(duì)程序性能影響很大,應(yīng)盡量避免不必要的過(guò)程調(diào)用,特別是遞歸調(diào)用。
非靜態(tài)局部變量的存儲(chǔ)分配非靜態(tài)局部變量占用的空間分配在本過(guò)程的棧幀中C標(biāo)準(zhǔn)中,沒(méi)有規(guī)定必須按順序分配,不同的編譯器有不同的處理方式。C標(biāo)準(zhǔn)明確指出,對(duì)不同變量的地址進(jìn)行除==和!=之外的關(guān)系運(yùn)算,都屬未定義行為(undefinedbehavior)如,語(yǔ)句“if(&var1<&var2){...};”屬于未定義行為編譯優(yōu)化的情況下,會(huì)把屬于簡(jiǎn)單數(shù)據(jù)類型變量分配在通用寄存器中對(duì)于復(fù)雜數(shù)據(jù)類型變量,如數(shù)組、結(jié)構(gòu)和聯(lián)合等數(shù)據(jù)類型變量,一定會(huì)分配在棧幀中Windows/Linux中的存儲(chǔ)映像說(shuō)明了什么?注意:每個(gè)存儲(chǔ)區(qū)地址的特征!參數(shù)的地址總比局部變量的地址大!因?yàn)闂5纳L(zhǎng)方向:高地址→低地址
局部變量和參數(shù)都存放在:棧區(qū)LinuxWindows
總是最右邊參數(shù)的地址最大,因?yàn)閰?shù)入棧順序?yàn)椋河摇骔indows中局部變量的地址不一定連續(xù),也不一定按大小順序分配Windows中的存儲(chǔ)映像#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
說(shuō)明了什么?
Windows中棧區(qū)也是高地址向低地址生長(zhǎng)!param3=3param2=2param1=1
返回地址var3=3var2=2var1=1猜猜這里是什么?這里與Linux的差別是什么?EBP未壓棧!Windows中的存儲(chǔ)映像#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說(shuō)明了什么?注意:每個(gè)存儲(chǔ)區(qū)地址的特征!
全局變量和靜態(tài)變量連續(xù)存放在同一個(gè)存儲(chǔ)區(qū):可讀寫數(shù)據(jù)區(qū)局部變量存放在另一個(gè)存儲(chǔ)區(qū):棧區(qū)Windows/Linux中的存儲(chǔ)映像說(shuō)明了什么?注意:每個(gè)存儲(chǔ)區(qū)地址的特征!全局變量和靜態(tài)變量連續(xù)存放在同一個(gè)存儲(chǔ)區(qū):可讀寫數(shù)據(jù)區(qū)
局部變量存放在另一個(gè)存儲(chǔ)區(qū):棧區(qū)LinuxWindows選擇結(jié)構(gòu)的機(jī)器級(jí)表示
if~else語(yǔ)句的機(jī)器級(jí)表示
if(cond_expr)then_statementelseelse_statement
Jcc指令JMP指令I(lǐng)f-else語(yǔ)句舉例intget_cont(int*p1,int*p2){ if(p1>p2) return*p2; else return*p1;}p1和p2對(duì)應(yīng)實(shí)參的存儲(chǔ)地址分別為R[ebp]+8、R[ebp]+12,EBP指向當(dāng)前棧幀底部,結(jié)果存放在EAX。為何這里是”jbe”指令?switch-case語(yǔ)句舉例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é)邊界對(duì)齊。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)的機(jī)器級(jí)表示do~while循環(huán)的機(jī)器級(jí)表示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)的機(jī)器級(jí)表示
for循環(huán)的機(jī)器級(jí)表示
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僅為說(shuō)明原理,實(shí)際上可直接用公式,為說(shuō)明循環(huán)的機(jī)器級(jí)表示,這里用循環(huán)實(shí)現(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過(guò)程體中沒(méi)用到被調(diào)用過(guò)程保存寄存器。因而,該過(guò)程棧幀中僅需保留EBP,即其棧幀僅占用4字節(jié)空間,而遞歸方式則占用了(16n+12)字節(jié)棧空間,多用了(16n+8)字節(jié),每次遞歸調(diào)用都要執(zhí)行16條指令,一共多了n次過(guò)程調(diào)用,因而,遞歸方式比循環(huán)方式至少多執(zhí)行了16n條指令。由此可以看出,為了提高程序的性能,若能用非遞歸方式執(zhí)行則最好用非遞歸方式。
局部變量i和result被分別分配在EDX和EAX中。通常復(fù)雜局部變量被分配在棧中,而這里都是簡(jiǎn)單變量SKIP遞歸過(guò)程調(diào)用舉例intnn_sum(intn){ intresult; if(n<=0) result=0; else result=n+nn_sum(n-1); returnresult;}PSum(n)Sum(
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年挖機(jī)工程承包跨區(qū)域施工合同范本3篇
- 2025年水土保持項(xiàng)目生態(tài)保護(hù)合同樣本2篇
- 石家莊2025年度裝修工程合同范本2篇
- 二零二五版貨車駕駛員勞動(dòng)合同范本:社會(huì)保險(xiǎn)與福利待遇3篇
- 二零二五版XX型號(hào)花崗巖打磨翻新與安全防護(hù)承包協(xié)議3篇
- 二零二五年網(wǎng)絡(luò)安全設(shè)備采購(gòu)與安裝合同2篇
- 2025年淘寶店鋪網(wǎng)紅直播場(chǎng)景裝修合作協(xié)議3篇
- 2025年醫(yī)療保健及時(shí)專業(yè)調(diào)理服務(wù)協(xié)議
- 二零二五版房產(chǎn)經(jīng)紀(jì)人傭金結(jié)算及稅收籌劃合作協(xié)議3篇
- 2025年醫(yī)療美容特許經(jīng)營(yíng)協(xié)議
- 中國(guó)的世界遺產(chǎn)智慧樹(shù)知到答案章節(jié)測(cè)試2023年遼寧科技大學(xué)
- 急診與災(zāi)難醫(yī)學(xué)課件 03 呼吸困難大課何琳zhenshi
- 急性腹瀉與慢性腹瀉修改版
- 先天性肌性斜頸的康復(fù)
- 《國(guó)際市場(chǎng)營(yíng)銷》案例
- GB/T 37518-2019代理報(bào)關(guān)服務(wù)規(guī)范
- GB/T 156-2017標(biāo)準(zhǔn)電壓
- PPT溝通的藝術(shù)課件
- 內(nèi)科學(xué):巨幼細(xì)胞性貧血課件
- 暑假家校聯(lián)系情況記錄表
- 周計(jì)劃工作安排日程表Excel模板
評(píng)論
0/150
提交評(píng)論