王雪 原創(chuàng)作品轉(zhuǎn)載請注明出處 《linux內(nèi)核分析》MOOC課程 http://mooc.study.163.com/course/USTC-1000029000
一、理論基礎(chǔ) (1)馮諾依曼體系結(jié)構(gòu):存儲程序計算機的工作模型 從硬件角度看程序的執(zhí)行過程:其中ip(instruction pointer)為CPU中的寄存器,指向內(nèi)存中的某一塊,CPU執(zhí)行指令時,會從IP中取出一條指令后執(zhí)行,執(zhí)行過后,IP自加一(增加一個指令的長度),取下一條指令執(zhí)行。 從程序員的角度看: CPU是一個大的for循環(huán),不停地執(zhí)行next instruction命令,存儲器主要負責(zé)數(shù)據(jù)和代碼等信息的存儲,CPU與Main Memory通過總線進行連接。 注意: 1.程序員不可以直接修改IP的值,只能通過一些指令,如CALL、RET、JMP等間接修改IP的值 2.IP在32位機器中表示為eip(本次實驗以32位作為分析),在64位機器中表示為rip。 (2)x86匯編基礎(chǔ)知識(32位機器) 一.寄存器:在x86體系中,寄存器可分為通用寄存器、段寄存器、標志寄存器 1通用寄存器: EAX:累加器 EBX:基地址寄存器 ECX:計數(shù)寄存器 EDX:數(shù)據(jù)寄存器 EBP:堆棧基指針 ESI,EDI:變址寄存器 ESP:堆棧頂指針 2.段寄存器:CS,DS,ES,SS,FS,GS 3.標志寄存器 CPU在實際取指令時根據(jù)CS:eip來準確確定某一個指令在內(nèi)存中的地址。 二:匯編指令(以常見的MOV,PUSH,POP,CALL等進行說明) (1)MOV指令及尋址方式 1.MOV指令,能實現(xiàn)以下操作: ① CPU內(nèi)部寄存器之間數(shù)據(jù)的任意傳送(除了碼段寄存器CS和指令指針I(yè)P以外)。 ② 立即數(shù)傳送至CPU內(nèi)部的通用寄存器組(即AX、BX、CX、DX、BP、SP、SI、DI),給這些寄存器賦初值。 ③ CPU內(nèi)部寄存器(除了CS和IP以外)與存儲器(所有尋址方式)之間的數(shù)據(jù)傳送,可以實現(xiàn)一個字節(jié)或一個字的傳送。 ④ 能實現(xiàn)用立即數(shù)給存儲單元賦初值。 movb,movl,movw,movq分別針對8位,16位,32位,64位系統(tǒng) (2)pushl和pop指令,pushl用于入棧(棧的擴張),pop用于出棧(棧的收縮) 棧是向下生長的,也就是說棧底位于高地址,棧頂位于低地址,用ebp指向棧底,用esp指向棧頂。 入棧操作:pushl %eax完成的操作包括兩步
出棧操作:pop %eax完成的操作包括兩步
movl (%esp),%eaxaddl $4,%esp(3)CALL主要用于函數(shù)調(diào)用 call 0x12345 完成的操作包括兩步
push %eipmovl %0x12345,%eip(4)RET指令用于恢復(fù)操作,完成pop %eip操作 (5)enter和leave操作 enter 置為空棧,完成的操作包括兩步
pushl %ebpmovl %esp,%ebpleave用于撤銷函數(shù)調(diào)用堆棧,完成的操作包括兩步
movl %ebp,%esppopl %ebp注: (1)函數(shù)調(diào)用堆棧是由邏輯上多個堆棧疊加起來的(比如函數(shù)的嵌套) (2)函數(shù)的返回值默認使用eax寄存器存儲返回給上一級函數(shù) (3)一定要注意的是eip不能由程序員直接修改,程序員想修改eip只能通過特殊指令間接修改。 2.尋址方式 (1)寄存器尋址(不訪問內(nèi)存) movl % eax,% edx <==>edx= eax,將eax中的值賦值給edx (2)立即尋址(不訪問內(nèi)存)用$表示立即數(shù) movl $ 0x1234,%edx <==>edx = 0x1234 (3)直接尋址 movl 0x123,%edx <==>edx = * (int32_t*)0x123 將內(nèi)存地址0x123所指向的內(nèi)存數(shù)據(jù)賦值給edx (4)間接尋址 movl (%ebx),%edx <==>edx = * (int32_t*)ebx (5)變址尋址 movl 4(%ebx),%edx <==>edx = * (int32_t*)(ebx+4) 二、通過實驗分析計算機是如何工作的 (1)實驗代碼與截圖 在實驗樓的linux終端下創(chuàng)建一個main.c文件(注意實驗樓的環(huán)境為64位) 利用指令(64位下生成32位的匯編文件)
進入main.s匯編文件,去掉所有以.開始的代碼行(以.開始的代碼是連接時的輔助信息)得到純匯編代碼
可以看到剛才介紹過的指令操作。 (2)實驗分析——-對執(zhí)行過程的分析 與C語言類似,匯編代碼的入口也為main函數(shù) 初始時棧的狀態(tài)
進入main函數(shù),執(zhí)行18行代碼
執(zhí)行后棧的狀態(tài) 0標號下下存放ebp的內(nèi)容,esp指向標號1處
esp和ebp指向相同位置
執(zhí)行call時實際執(zhí)行兩個動作,pushl %eip ; movl f ,%eip 此時eip指向第23行代碼 執(zhí)行后,eip指向f 跳轉(zhuǎn)到f中執(zhí)行:
在執(zhí)行過movl%esp,%ebp后,esp和ebp置于相同的標號處(4) 執(zhí)行subl $4,%esp,esp向下移動到標號5
movl 8(%ebp),%eax 變址尋址,將ebp(此處為標號4)加8(向上移動兩個標號,也就是標號2處)的值賦給eax,所以%eax = 8 movl %eax,(%esp),將eax的內(nèi)容也就是8賦值到esp下也就是標號5處
執(zhí)行call時實際執(zhí)行兩個動作,pushl %eip ; movl g,%eip 此時eip指向第15行代碼leave的位置,此時eip指向g跳轉(zhuǎn)到g中去執(zhí)行 在g中執(zhí)行:
pushl %ebp同上,將esp向下移動,將ebp(標號為4)壓棧 movl %esp,%ebp esp和ebp指向相同的位置
強ebp向上移動兩個標號的值(也就是8)賦給eax
addl $57,%eaxpopl %ebpret%eax中存放的值為8,addl操作,將eax的值與立即數(shù)57相加,結(jié)果為65,將65存回到eax popl %ebp,將ebp的值放回到ebp,執(zhí)行效果:ebp重新指向標號為4的位置,同時esp減4 ret執(zhí)行popl %eip,也就是說esp向上移動指向5的標號的位置,同時eip指向15行指令的位置(call的下一條指令)
回到f中執(zhí)行
leave執(zhí)行兩條指令, movl %ebp,%esp popl %ebp 首先,將esp指向ebp相同的位置(也就是標號4的位置),popl %ebp,將ebp出棧,此時ebp指回標號1的位置,由于popl,esp向上移動
ret執(zhí)行popl %eip 由于popl,esp向上增加一個,指向標號2,eip指向第23行代碼處
eip執(zhí)行第23行代碼,回到main處,執(zhí)行
eax此時的值為65,執(zhí)行addl,65+1 = 66,將66存回到eax。 函數(shù)返回值默認使用eax來存儲 執(zhí)行l(wèi)eave,分為兩步, movl %ebp,%esp,將esp指向ebp的位置,popl %ebp,將ebp出棧(ebp指向0的位置),popl指令時esp向上移動,也就是說esp,ebp均指向標號0的位置,棧回到main函數(shù)最初的狀態(tài)。 ret,return的是main函數(shù)之前的堆棧,此處由操作系統(tǒng)管理。 棧向下生長,向上還原,增增減減,將程序變?yōu)橹噶盍鳎瑥腃PU上流過。 此時,小程序執(zhí)行完成 三、實驗總結(jié)–對計算機如何工作的理解 1.計算機的基本原理是存儲程序和程序控制,預(yù)先要把指揮計算機如何進行操作的指令序列(稱為程序)和原始數(shù)據(jù)通過輸入設(shè)備輸送到計算機內(nèi)存貯器中。每一條指令中明確規(guī)定了計算機從哪個地址取數(shù),進行什么操作,然后送到什么地址去等步驟。 計算機在運行時,先從內(nèi)存中取出第一條指令,通過控制器的譯碼,按指令的要求,從存儲器中取出數(shù)據(jù)進行指定的運算和邏輯操作等加工,然后再按地址把結(jié)果送到內(nèi)存中去。接下來,再取出第二條指令,在控制器的指揮下完成規(guī)定操作。依此進行下去。直至遇到停止指令。簡單來說就是CPU負責(zé)處理和運算,存儲器負責(zé)保存指令和數(shù)據(jù)。通過操作系統(tǒng)得調(diào)度和安排,不停地進行取址、譯碼、執(zhí)行的循環(huán)。 2.匯編代碼是什么? 計算機語言的發(fā)展過程從機器語言(計算機能直接識別的二進制0和1的組合)->匯編語言(為了減輕使用機器語言編程的痛苦,人們進行了一種有益的改進:用一些簡潔的英文字母、符號串來替代一個特定的指令的二進制串,依賴于硬件)->高級語言(接近于數(shù)學(xué)語言或人的自然語言,同時又不依賴于計算機硬件,編出的程序能在所有機器上通用)。 我們編寫了一個小程序,比如上面實驗中寫到的main.c文件,編譯器執(zhí)行的過程,
可執(zhí)行的二進制文件是計算機“認識”的文件,可以直接執(zhí)行。 3.以上便是我對這次實驗的總結(jié),計算機很“單純”,它可以執(zhí)行很多復(fù)雜的指令,但它也是被“告訴”要執(zhí)行什么,才會去執(zhí)行什么,通過對匯編語言的分析可以方便我們理解計算機處理的過程,了解計算機如何工作等等,這也會成為我今后學(xué)習(xí)的重點。感謝為我們辛苦準備課程的老師!
新聞熱點
疑難解答
圖片精選