<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] ## 環境準備 ### 虛擬機 這里我使用的虛擬機是:[virtualbox](https://www.virtualbox.org/wiki/Downloads) ![](https://img.kancloud.cn/57/f7/57f79fbd0287f3540d67d23fba1e2848_1281x629.png) ### 鏡像 鏡像使用的[Ubuntu 20.04.2.0 LTS](http://releases.ubuntu.com/20.04/) ![](https://img.kancloud.cn/33/2a/332a6f0c3d68e438bf965347ae8322f4_1284x687.png) 關于virtualbox環境設置沒什么說的,網絡記得啟用并且使用橋接模式即可 ![](https://img.kancloud.cn/c6/11/c611bdec9462dbcc4d29bf3a8cfa50c2_863x569.png) ### 安裝gcc,vim,git 這個就很簡單了三條命令 `sudo apt-get update` `sudo apt-get install gcc` `sudo apt-get install vim` `sudo apt-get install git` ## 開始編碼 ### HelloWord 還是從C語言最開始的HelloWorld開始 ```c #include "stdio.h" int main(int argc, char const *argv[]) { printf("Hello World!\n"); return 0; } ``` ![](https://img.kancloud.cn/30/dc/30dcbfb84151099de6faf38527000ddb_414x162.png) ### 程序編碼過程 使用gcc編譯這段代碼 `gcc HelloWorld.c -o HelloWorld` 然后執行發現執行成功 ![](https://img.kancloud.cn/03/f9/03f916cdf95c31609129f350c1e7b9ea_690x156.png) gcc -o 只是完成編譯工作的驅動程序,它會根據編譯流程分別調用**預處理程序**、**編譯程序**、**匯編程序**、**鏈接程序**來完成具體工作。 接下來對比著圖片按照每一個步驟編譯一下這個程序來提升一下對這個過程的理解: ![](https://img.kancloud.cn/ac/85/ac8576000382550178084aeab2022886_3015x2410.png) #### 源文件生成預處理文件,加入頭文件,替換宏。 `gcc -E HelloWorld.c -o HelloWorld.i ` #### 預處理文件生成編譯文件 `gcc -S HelloWorld.i -o HelloWorld.s ` #### 編譯文件生成匯編文件: `gcc -c HelloWorld.s -o HelloWorld.o ` #### 匯編文件生成可執行文件: `gcc HelloWorld.o -o HelloWorld ` #### 源文件生成可執行文件: `gcc HelloWorld.c -o HelloWorld ` #### Linux系統運行可執行文件: `./HelloWorld` ### 程序裝載執行 在講到這里的時候彭東老師提到了圖靈機和馮諾依曼,這里我把中專欄的圖片貼出來,我感覺這兩個概念只要理解即可,所以不做深入學習,理解即可,他們只是計算機形成過程中的幾個基礎理論或者說必要條件。![](https://img.kancloud.cn/88/07/8807afe9e6991dff6e0caee41a26488a_1386x1026.png) ### 更形象地將 HelloWorld 程序裝入原型計算機 #### 反匯編特定指令機器碼 使用**objdump**從objfile中反匯編那些特定指令機器碼的section `objdump -d HelloWorld` ![](https://img.kancloud.cn/41/15/41155454015deb996b0791c9e7a8dcad_701x287.png) 第一列為地址; 第二列為十六進制,表示真正裝入機器中的代碼數據; 第三列是對應的匯編代碼; 第四列是相關代碼的注釋。這是 x86_64 體系的代碼,由此可以看出 x86 CPU 是變長指令集。 #### 將代碼裝入上面圖靈機+馮諾依曼體系結構 ![](https://img.kancloud.cn/27/f1/27f11e2facb7088a65434606e2f07656_3810x1815.png) #### 以上知識涉及到知識盲區查閱的資料 ##### 匯編中的棧幀理解 ###### 基本概念 引用百度百科的介紹:C語言中,每個棧幀對應著一個未運行完的函數。棧幀中保存了該函數的返回地址和局部變量。棧幀也叫過程[活動記錄](https://baike.baidu.com/item/%E6%B4%BB%E5%8A%A8%E8%AE%B0%E5%BD%95),是[編譯器](https://baike.baidu.com/item/%E7%BC%96%E8%AF%91%E5%99%A8)用來實現過程/[函數調用](https://baike.baidu.com/item/%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8)的一種數據結構。可以理解為:棧幀就是存儲在用戶棧上的(當然內核棧同樣適用)每一次函數調用涉及的相關信息的記錄單元。 ###### 分析棧幀的記錄活動 簡單用c寫個函數調用的demo ![](https://img.kancloud.cn/4a/56/4a565f2c1b4fbad02e9e5e77330a2334_382x251.png) 使用objdump命令反匯編看一下 ![](https://img.kancloud.cn/47/4a/474a822dded52293e79cf10152094132_859x490.png) > x86\_64通用寄存器 > %rax 通常用于存儲函數調用的返回結果,同時也用于乘法和除法指令中。 > %rsp 是堆棧指針寄存器,通常會指向棧頂位置 > %rbp 是棧幀指針寄存器,用于標識當前棧幀的起始位置 > %rdi,%rsi,%rdx,%rcx,%r8,%r9 用來傳遞函數參數,依次對應第1參數,第2參數至第6參數 > %rbx,%r12,%r13,%14,%15 ,%r10,%r11 用作數據存儲,屬于通用性更為廣泛的寄存器,編譯器或匯編程序可以根據需要存儲任何數據。 ![](https://img.kancloud.cn/24/ab/24ab569ffffbf3a5861a51ac29e4304a_1695x648.png) ## 課后思考題 為了實現 C 語言中函數的調用和返回功能,CPU 實現了函數調用和返回指令,即上圖匯編代碼中的“call”,“ret”指令,請你思考一下:call 和 ret 指令在邏輯上執行的操作是怎樣的呢? 經過上面的代碼分析,已經可以解決這個問題了,下面附一些精彩留言以供參考。 > 針對第一個問題,在gcc編譯完成之后,函數對應的指令序列所在的位置就已經確定了,因此這是編譯階段需要考慮的問題 。 > 至于第二個問題,在執行完call指令的同時,需要將call指令下面一條指令的地址保存到棧內存中,同時更新%rsp寄存器指向的位置,然后就可以開始執行被調函數的指令序列,執行完畢后,由ret指令從rsp中獲取棧頂的returnadress地址,然后跳轉到call的下一條指令繼續執行 >call和ret其實是一對相反指令,調用call時會將當前IP入棧,即push IP,然后執行跳轉即jmp,而ret也是將棧中的IP推出寫入IP寄存器,即pop IP。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看