從C到彙編:棧是電腦工作的基礎

来源:http://www.cnblogs.com/r1ce/archive/2016/02/23/5209519.html
-Advertisement-
Play Games

作者:r1ce 原創作品轉載請註明出處 《Linux內核分析》 MOOC課程http://mooc.study.163.com/course/USTC-1000029000 關於電腦是如何工作的,這是一個容易概括卻難以詳解的問題。大家非常清楚的馮諾依曼體系,以存儲程式為最重要的特性,實際上就是CP


         作者:r1ce        原創作品轉載請註明出處       《Linux內核分析》 MOOC課程http://mooc.study.163.com/course/USTC-1000029000          關於電腦是如何工作的,這是一個容易概括卻難以詳解的問題。大家非常清楚的馮諾依曼體系,以存儲程式為最重要的特性,實際上就是CPU像一個大管家一樣,通過種種方式在浩如煙海的記憶體中,找出需要執行的指令,和需要使用的數據。那麼CPU如何區分指令和數據,如何知道確定指令執行的順序呢?        我們先從上至下來看電腦。普通用戶使用電腦上的軟體,軟體是由程式員編寫的,一般使用高級語言,如Python、C、Java等,這些語言易於人類理解、閱讀和編寫,但是電腦卻不能直接識別。無論是Python還是C,前者需要通過解釋器來執行,後者需要編譯器編譯為可執行文件。電腦最底層的實現是基於電路實現0和1的識別,這也是可執行文件的真貌——一大堆0和1的表示。那麼高級語言到0和1之間,看起來好像隔著很大的一條鴻溝,於是彙編語言作為二者的中介,便顯得十分重要了。向上而言,高級語言可以用彙編語言表示;向下而言,每一個彙編語言的指令都可以用二進位0和1表示,從而被電腦CPU識別。理解了彙編語言的操作過程,也就能夠理解電腦究竟是如何工作的。        彙編語言究竟是什麼東西呢?想要理解彙編語言,要先理解電腦的組成。為了簡化,只提CPU和記憶體。CPU是處理器,記憶體存放著指令和數據,處理器就像一個管家,從記憶體中取指令執行,對數據進行出來,並將數據儲存起來。對於CPU來說,每一個程式的執行要解決三個問題:1. 待處理的數據在哪裡;2. 如何處理數據;3. 處理好的數據放在哪裡。為瞭解決這三個問題,CPU需要藉助一些工具的幫助,這些工具就是各種寄存器。彙編語言實際上就是對這些寄存器進行處理,通俗點說,就是把一大堆數據在寄存器和記憶體倒騰過來倒騰過去,做一些複製和加加減減的運算。其實學習彙編語言很簡單,只要記住十幾條彙編指令和各種寄存器以及堆棧的用法就可以了。        在這篇文章中,我們通過對一個簡單的C程式反彙編得到彙編代碼,分析彙編代碼來瞭解電腦工作的基礎。        這段C程式是這樣的:
 1 int a(int x)
 2 {
 3       return x + 5;
 4 }
 5 
 6 int b(int x)
 7 {
 8       return a(x);
 9 }
10 
11 int main(void)
12 {
13       return b(5) - 2;
14 }
       可以看到程式中有很多函數的調用和返回。為什麼要這樣設置呢?因為程式中的函數調用時電腦工作運行的關鍵,分析函數調用的具體實現能夠幫助理解電腦運行的原理。        我們將上述代碼寫入main.c文件中。然後使用
gcc -S -o main.s main.c -m32

       命令生成彙編代碼。結果如下圖。後面加-m32是為了讓其按照32位的方式反彙編。

 

       我們只需要看彙編代碼的關鍵部分,可以把點開頭的語句全部刪去,得到如下的彙編指令。

 1 a:
 2 
 3     pushl    %ebp
 4     movl    %esp, %ebp
 5     movl    8(%ebp), %eax
 6     addl    $5, %eax
 7     popl    %ebp
 8     ret
 9 
10 b:
11 
12     pushl    %ebp
13     movl    %esp, %ebp
14     subl    $4, %esp
15     movl    8(%ebp), %eax
16     movl    %eax, (%esp)
17     call    a
18     leave
19     ret
20 
21 main:
22 
23     pushl    %ebp
24     movl    %esp, %ebp
25     subl    $4, %esp
26     movl    $5, (%esp)
27     call    b
28     subl    $2, %eax
29     leave
30     ret
       接下來我們分析C代碼和彙編程式究竟是如何對應起來的,以及彙編語言是如何工作的。        我們先看C程式,從main函數看起,它返回了一個函數b再進行運算的結果。那麼我們來看函數b,它返回的是函數a的結果,而函數a的作用是將傳遞給它的參數x加5。所以對於這個程式,最後得到的數值應該是5+5-2=8。        再來看彙編代碼,我們還是從main函數看起,一條指令一條指令地分析。第n條表示指令執行的順序,後面列出了代碼的行號和執行的指令。        第1條:23 pushl %ebp        一看到push,我們就知道這是在對棧進行操作。ebp是棧頂指針,esp是棧當前位置指針,棧是自上向下生長的,後進先出。先把ebp壓棧,實際上是先將esp-4再將ebp放到棧當前位置。        第2條:24 movl %esp, %ebp        將esp的值放到ebp中,也就是說現在ebp的指向改變為esp的指向。        第3條:25 subl $4, %esp        將esp-4。        第4條:26 movl $5, (%esp)        將5移入esp指向的地址中。        第5條:27 call b        調用函數b,這裡等於兩個操作,一個是先將現在的eip入棧,此時eip應為subl $2,%eax這條指令的位置,我們記為28。另一個操作是將b函數的地址放入eip,也就是說此時程式要從10開始執行。        第6條:12 pushl %ebp        第7條:13 movl %esp, %ebp        第8條:14 subl $4, %esp        此時已跳轉到b函數,指令之前已經講過了,與7、8條一起不再贅述。        第9條:15 movl 8(%ebp), %eax        movl 8(%ebp), %eax,是將ebp的值+8指向的內容放入eax,實際上就是eax = 5。        第10條:16 movl %eax, (%esp)        將eax的內容放入現在esp指向的內容中。        第11條:17 call a        調用函數a,與前面的步驟類似。        第12條:3 pushl %ebp        第13條:4 movl %esp, %ebp        第14條:5 movl 8(%ebp), %eax        是a函數的pushl %ebp,與13、14條一同省略。        第15條:6 addl $5, %eax        將eax中的值+5得到10。        第16條:7 popl %ebp        將現在esp指向的內容放入ebp,esp+4,所以現在ebp=4。        第17條:8 ret        是ret,即popl %eip,也就是現在的eip更改為18,回到函數b,從leave開始執行。        第18條:18 leave        leave,表示兩條指令,movl %ebp,%esp和popl %ebp。        第19條:19 ret        ret回到main函數,從28處執行。        第20條:28 subl $2, %eax        將eax中的內容-2,即8。        第21條:29 leave        第22條:30 ret        如圖所示。從圖中我們可以看到,棧又回到了初始的位置。               至此,彙編代碼就分析完了。        從上面的過程可以看出,電腦最本質的工作原理,是對存儲的數據進行處理,並把結果保存,然後不斷迴圈這個處理數據的過程。指令就是對數據進行處理的依據。具體的方法就是藉助CPU中的寄存器,以及記憶體中的棧,依據一個約定的步驟對數據進行操作。電腦其實很簡單,它是一個認死理的家伙,只要確定了每一步要做什麼,它就會嚴格地按照步驟把操作完成,絕對不打折扣。因此,相比與人打交道,與電腦打交道可是要輕鬆多了。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • mkdir dir1 創建一個叫做dir1的目錄 pwd 顯示工作路徑 cat filename 顯示文件信息
  • 1.插入U盤,磁碟工具,格式化U盤為Mac OS X拓展 (日誌式); 2.去網站搜索recovery disk assistant,此文件大約1.1M,直接打開使用它製作啟動盤,進度條完畢就完成了。 (這個文件我下載好了,在spotlit裡面搜索recoverydiskassistant就找到了)
  • cd -> 變換路徑 //文件一般存在/var/路徑下,var為可修改存儲盤 ls -> 列出所有隱藏文件與相關文件的屬性 #ls -al #ls -al -rwxrwxrwx 1 root root 293 2016-02-23 test 文件屬性 連接數 文件擁有者 文件所屬用戶組 大小 時間
  • 一、什麼是SSH? 簡單說,SSH是一種網路協議,用於電腦之間的加密登錄。 如果一個用戶從本地電腦,使用SSH協議登錄另一臺遠程電腦,我們就可以認為,這種登錄是安全的,即使被中途截獲,密碼也不會泄露。 最早的時候,互聯網通信都是明文通信,一旦被截獲,內容就暴露無疑。1995年,芬蘭學者Tatu
  • 1. 先編輯一個解壓腳本ins.sh 1 #!/bin/bash 2 preline=10 3 line=`wc -l $0|awk '{print $1}'` 4 line=`expr $line - $preline` 5 tail -n $line $0 |tar xz -C ./ 6 #do
  • 安裝 Centos 7後, 習慣性的安裝 Xmanager 3或4, 都不能正常工作, 無奈之下開始安裝 VNCServer。 (個人習慣使用Xmanager, 因為不需要安裝,只要配置一下就能用, 而且一直很穩定) 為了節省以後安裝 vncserver 的時間,寫這篇文章作備忘用 安裝/配置: 使
  • 這是一個關於怎樣在你的 CentOS 7 上安裝配置 VNC 服務的教程。當然這個教程也適合 RHEL 7 。在這個教程里,我們將學習什麼是 VNC 以及怎樣在 CentOS 7 上安裝配置 VNC 伺服器 。 我們都知道 這是一個關於怎樣在你的 CentOS 7 上安裝配置 VNC 服務的教程。當
  • 【一些前言廢話】一名web開發尤其是後端不懂LAMP環境的搭建,那就攤上事了,有些人說他一直用win下的wampServer這種傻瓜式環境搭建,用的挺好的,也有人說他用雲伺服器,搭配“一鍵搭建LAMP環境”大法也挺好用的,是的,這些在初學的時候都是可以先用上的,但是“不知其所以然”的習慣一旦養成,很
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...