1. 程式人生 > >從彙編指令細看計算機程式的執行過程

從彙編指令細看計算機程式的執行過程

一、相關知識點:

1、x86彙編中intel 語法與AT&T語法的區別:

X86 彙編存在兩種不同的語法:inter語法和AT&T語法,在windows平臺上通常使用的是inter語法,二在UNIX/linux平臺的彙編器使用的則一直是AT&T語法。

inter語法相比,AT&T語法的特點有:

(1) 、暫存器前面用字首來標識;

(2) 、指令中源運算元在前目的運算元在後;(與inter語法剛好相反)

(3) 、運算元的長度通過在指令字元後新增字尾來卻定,表示 8位,表示16位,表示32位。例如:movl  %esp  %ebp,  表示將暫存器

esp 中的值複製到 寄存   器ebp中。

(4) 、立即數用“$”來標識,例如:addl  $5  %eax  表示將暫存器eax 中的值加5

(5) 、變數前面加'$"表示不同的意義,例如:movl  $g  %eax   表示把 的地址存到eax中, 而 movl g  %eax 表示把變數的值存到eax中 (類似於函式引數傳遞   中的引用傳遞與值傳遞的區別)

2、push ,  pop , call , ret , enter , leave 等指令的等效形式:

這裡有一個小錯誤:ret指令的等效形式應該是 popl eip,因為ret 的目的是改變程式的流向,retf 是遠跳轉 相當於:popl eip ; popl cs 。

二、準備工作:

1、首先我們先寫一個簡單的C程式:

2、然後將這個C檔案編譯成彙編檔案:gcc -S -o main.s main.c 

               

3、去掉彙編檔案中以點開頭的標號和指令(用於連線)後得到乾淨的彙編程式碼,接下來我們將根據以下彙編程式碼來模擬計算機的指令執行過程。

三、彙編程式碼分析:

1、從main函式開始執行,假設進入main函式之前,堆疊的棧底指標ebp指向2000,棧頂指標esp指向2000


2、假設函式f 的入口地址為:0x1234,指令指標ip指向0x3456 


3、ip指標指向了飛函式的入口地址後開始執行函式

                            

4、接下來將跳轉到函式g,假設函式g 的入口地址為:0x2234,此時指令指標指向:0x1248

此時指令指標指向了0x1248,也就是回到呼叫函式g之前的那條指令的下一條指令(f函式中)

5、計算機又回到了函式 f 中:


   此時指令指標指向了0x3456,也就是回到呼叫函式 f 之前的那條指令的下一條指令(main函式中)

6、計算機又回到了main函式中:


因為eax 之前的值為13,所,現在eax=13+9=22


此時經過ret 指令後,計算機退出了main 函式,程序結束。

總結:

通過以上的操作,完成了簡單的從C語言到組合語言,在模擬計算機執行彙編指令的全過程,編寫的程式雖然很簡單但很有代表性,包含了函式呼叫與引數傳遞,以及在程式執行中的堆疊變化,以及引數值在各個暫存器之間的傳遞與運算。

組合語言不可否認要比C語言複雜、難寫、難讀,但是經過這樣一個過程後,對彙編程式沒有之前那麼抵觸。彙編與C語言在本質上也都一樣,只是表達的形式不同。C語言中運用的是不同的變數來”儲存“和傳遞引數,而組合語言則是使用堆疊、暫存器來“儲存”和傳遞引數,最終都是由運算器計算,C語言中的變數可以隨意定義,但是彙編中堆疊空間和暫存器數量都有限,就像漢諾塔遊戲中,給你無限多根柱子問題很容易就能解決,但是隻給三根柱子問題就變得很繁瑣。程式的最終目的不是解決問題,而應該是高效率的解決問題。所以一個寫一個好的C語言程式只是第一步,還要有好的編譯器等工具,為C程式最終要變成2進位制程式碼交給計算機執行。