从一段代码的汇编看计算机的工作原理
朱宇軻?+ 原創(chuàng)作品轉(zhuǎn)載請注明出處 + 《Linux內(nèi)核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000
/*-------------------------------------以下內(nèi)容是課堂筆記,咿呀咿呀呦!------------------------------------------*/
本課主要對計算機的運行原理和匯編語言進行了簡單的介紹。
馮若依曼體系結(jié)構(gòu)即存儲程序計算機,也就是將程序?qū)懺趦?nèi)存中,由CPU通過總線從內(nèi)存中讀取一條條程序,根據(jù)程序的內(nèi)容執(zhí)行具體的步驟。
如圖所示
CPU在讀取指令時,通過寄存器IP來指向下一條指令(如果是32位系統(tǒng),則為EIP)
CPU的寄存器分為通用寄存器、段寄存器、狀態(tài)寄存器
四種尋址方式:
movl %eax,%edx ? ? edx=eax ? ??? ? ? ? ? ? ? ? ? ? ?寄存器尋址
movl $0x123,%edx ?edx=0x123 ? ? ?? ? ? ? ? ? ? ? ?立即尋址
movl 0x123,%edx ? ?edx=*(int32_t*)0x123? ? ? ? 直接尋址
movl (%ebx),%edx ? edx=*(int32_t*)ebx ?? ? ? ? ?間接尋址
movl 4(%ebx),%edx ?edx=*(int32_t*)(ebx+4)? ? 變址尋址
了解pushl、popl、call 0x12345、ret命令
注意:IP寄存器一般不能隨便修改,只能通過call、ret等命令更改!
函數(shù)的返回值默認使用EAX寄存器存儲返回給上一級函數(shù)
? ??
/*-------------------------以下內(nèi)容是實驗分析,咿呀咿呀呦!------------------------------------------*/
? ? ?首先寫下這么一段C程序:
1 //linux.c 2 int g(x) 3 { 4 return x+3; 5 } 6 int f(x) 7 { 8 return g(x); 9 } 10 int main() 11 { 12 return f(10)+1; 13 }在Linux的環(huán)境中輸入如下指令:
gcc –S –o linux.s linux.c -m32然后打開linux.s,就可以看到我們匯編后的代碼(直接上截圖了)
將里面以“.”開頭的行去掉(這是為鏈接用的),得到匯編后的代碼:
1 g: 2 pushl %ebp 3 movl %esp, %ebp 4 movl 8(%ebp), %eax 5 addl $3, %eax 6 popl %ebp 7 ret 8 f: 9 pushl %ebp 10 movl %esp, %ebp 11 subl $4, %esp 12 movl 8(%ebp), %eax 13 movl %eax, (%esp) 14 call g 15 leave 16 ret 17 main: 18 pushl %ebp 19 movl %esp, %ebp 20 subl $4, %esp 21 movl $10, (%esp) 22 call f 23 addl $1, %eax 24 leave 25 ret? 接下來我們來分析一下改程序具體的流程。
程序一開始,CPU的IP寄存器指向匯編代碼的第18行,假設(shè)堆棧在內(nèi)存中的地址分別為0,1,2,3……堆棧基指針寄存器(EBP)和堆棧頂指針寄存器(ESP)均指向堆棧段0處。
第18~21行首先為main函數(shù)開辟新的內(nèi)存區(qū)域,之后將傳的參數(shù)10入棧,此時堆棧段如下所示:
然后程序調(diào)用call 函數(shù),將IP入棧,IP指向代碼第9行f處。
在f函數(shù)的代碼處,首先為f函數(shù)開辟新的內(nèi)存區(qū)域,接著將傳入的參數(shù)10賦值給EAX,并將EAX入棧,此時堆棧段內(nèi)存如下圖:
程序在此調(diào)用call進入g函數(shù)。在g函數(shù)中,同樣先是開辟內(nèi)存空間,然后將參數(shù)傳給EAX,并將EAX的值加上3。
之后將EBP出棧,并調(diào)用ret命令。此時IP重新指向f函數(shù)call之后的命令,堆棧內(nèi)存的情況如下:
之后就是不斷的調(diào)用leave與ret命令,跳出當前的內(nèi)存區(qū)域,回到上一級函數(shù)的內(nèi)存區(qū)域中,并將EAX的值加3,直到跳出main函數(shù),至此程序結(jié)束。
從上面的分析中,我覺得可以歸納出以下幾點:
1.計算機的運行流程確是遵循馮諾依曼框架,CPU將內(nèi)存中的代碼和數(shù)據(jù)讀取到自己的寄存器中,再根據(jù)一條條命令調(diào)用寄存器進行進一步的操作。
2.在進入每一個程序之前,CPU都會將上一級的EIP和EBP壓棧,相當于為新的函數(shù)重新開辟了一段新的內(nèi)存空間,直到退出函數(shù)的時候才將它們出棧。與此同時,將函數(shù)的返回值保存在EAX中。
3.CPU的各個寄存器都有不同的分工,如EIP指向要執(zhí)行的代碼,EAX存儲返回值等。它們貫穿于整個程序執(zhí)行流程,自己寫程序時一般不要輕易改動。
總結(jié)
以上是生活随笔為你收集整理的从一段代码的汇编看计算机的工作原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: QT源码解析(一) QT创建窗口程序、消
- 下一篇: VS2008编译汇编程序的问题