電腦是如何工作的?

來源:互聯網
上載者:User

標籤:電腦語言   linux   組合語言   mooc   

    此篇文章出於完成作業的目的,同時也總結一下自己的學習的體會,鞏固一下學習成果。是完全真實的作業過程。如需轉載請保留以下資訊:

    陳鐵 + 原創作品轉載請註明出處 + 《Linux核心分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000。


    今天電腦已經成為我們生活中重要不可分離的重要組成部分,從隨身攜帶的手機到超級電腦,大部分都遵循馮諾伊曼體繫結構:儲存程式、順序執行。程式編製好後,通過輸入裝置提供給電腦順序執行。只要人可以將需要解決的問題描述為電腦可以順序執行的指令序列,電腦就可以給出相應的結果。所以人們編製了電腦語言用來描述問題,現代電腦語言分為低級語言和進階語言,低級語言更接近機器,進階語言更接近人類。為了描述電腦的工作過程,我們採用接近機器的組合語言(組合語言)描述電腦的執行過程。

    實驗環境的主機作業系統是Windows7 64位,運行VirtualBox 4.3.20 Edition,虛擬機器安裝CentOS7.0 64bit,Linux kernel 3.10.0。gcc版本4.8.2,gdb版本GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-51.el7。

    以下是作業過程說明:

    1.C語言原始碼如下:

        #include <stdio.h>

        int g(int x) {
            return x+2;
        }
        int f(int x) {
            return g(x);
        }
        int main() {
            return f(7)+5;
        }

    2.執行命令進行gcc -S main.s main.c產生彙編代碼方便我們步進分析代碼的執行情況。執行gcc -g main.c -o main產生可用gdb調試的執行代碼。在linux終端下執行代碼情況如下:

    650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/5A/36/wKioL1T6j-nBaT5KAAEImRuKXiQ934.jpg" title="byxc.PNG" alt="wKioL1T6j-nBaT5KAAEImRuKXiQ934.jpg" />

    3.我們通過分析代碼流程也可以得到正確答案:

    程式從main開始執行,調用了f函數,把參數7傳過去賦給x。f函數又調用了g函數,把x也就是7傳過去,g函數得到參數x的值為7,返回7+2=9給f函數,f函數把9返回給main函數,main函數返回9+5=14作為程式的執行結果。在Linux終端下,14儲存在系統變數$?中。

    4.電腦系統我們可以抽象簡化為CPU、記憶體、輸入輸出幾部分。下面我們看一下這個程式在我的環境下,電腦是如何機械的的出這個14的。存在函數的程式會大量進行記憶體的堆棧操作,簡單的加法運算在此不展開介紹,重點對於堆棧的操作進行跟蹤。以下是cat main.s 所列出的彙編代碼,僅保留可執行檔部分。

g:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    %edi, -4(%rbp)
        movl    -4(%rbp), %eax
        addl    $2, %eax
        popq    %rbp
        ret
f:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $8, %rsp
        movl    %edi, -4(%rbp)
        movl    -4(%rbp), %eax
        movl    %eax, %edi
        call    g
        leave
        ret
main:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $7, %edi
        call    f
        addl    $5, %eax
        popq    %rbp
        ret


    (1)執行gdb main進入調試,l命令可以顯示出C語言代碼。break main設定斷點,使程式直行到程式開始處停下來,然後逐步執行,看一下電腦到底是如何工作的。run命令使程式開始執行。pushq %rbp;movq %rsp, %rbp後,此時rip指向rip=0x40051a。

    650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/5A/3A/wKiom1T6nhXiPrWIAAD7JKsRU-c586.jpg" title="brrun.PNG" alt="wKiom1T6nhXiPrWIAAD7JKsRU-c586.jpg" />

     (2)執行 info registers命令查看一下寄存器的情況。堆棧指標rbp和rsp指向相同的地址0x7fffffffe550,表明當前程式堆棧為空白。    650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/5A/36/wKioL1T6n8HzxPK9AAKPTqpeevM709.jpg" title="r1.PNG" alt="wKioL1T6n8HzxPK9AAKPTqpeevM709.jpg" />

這時彙編代碼儲存了堆棧原來的指標,作業系統開始調用main函數。可以看到rip指向下一條要執行指令的地址。

    (3)有函數調用,我們在gdb中執行stepi命令。執行movl    $7, %edi。

(gdb) stepi
0x000000000040051f      10              return f(7)+5;

(gdb) print $rip

$1 = (void (*)()) 0x40051f <main+9>

(gdb) print $edi
$1 = 7

    (4)這時把程式中傳給函數f的7儲存進了寄存器edi中,繼續執行,調用f函數。call f,執行的操作是當前rip=0x00400524值壓棧(在gdb中可以執行x %rsp命令查看),rsp-8,f函數所在地址放入rip中。電腦會執行f函數中的pushq $rbp;movq %rsp,%rbp;subq    $8, %rsp實際是儲存調用f函數前main函數的指標。此時rbp=0x7fffffffe540,rsp=0x7fffffffe538;而(rbp)儲存著調用前堆棧棧頂地址,當然棧頂移動8個位元組用來接受傳人的參數。

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/5A/36/wKioL1T6sJKBVs0QAABm80xKEpw225.jpg" title="r2.PNG" alt="wKioL1T6sJKBVs0QAABm80xKEpw225.jpg" />650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/5A/37/wKioL1T6w8Hxb6qSAABQ4dhCHlI438.jpg" title="r0.PNG" alt="wKioL1T6w8Hxb6qSAABQ4dhCHlI438.jpg" />                              

    (5)執行3次stepi命令,movl %edi, -4(%rbp);movl -4(%rbp), %eax;movl %eax, %edi 這三行指令很明確,從main傳過來的參數存入堆棧空間,然後通過eax寄存器儲存一下,在此放到edi中,準備傳給g函數。

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/5A/37/wKioL1T6xMSRqXxEAAE0ROZPtco453.jpg" title="r5.PNG" alt="wKioL1T6xMSRqXxEAAE0ROZPtco453.jpg" />

    (6)調用g函數時call g:rip值壓棧;rsp-8;g地址賦給rip。

    650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/5A/3B/wKiom1T6xM_Af9tcAAGql9M-r-A704.jpg" title="r6.PNG" alt="wKiom1T6xM_Af9tcAAGql9M-r-A704.jpg" />

    接下來執行兩條初始化指令pushq %rbp;movq %rsp, %rbp,儲存後rbp、rsp變成了0x7fffffffe528。movl %edi, -4(%rbp);movl -4(%rbp), %eax;addl $2, %eax,接受傳入的參數,通過eax執行加法,此時結果儲存在eax中。然後g函數執行恢複處理,popq  %rbp;ret,rsp指向0x7fffffffe538。

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/5A/36/wKioL1T6t2ygiag8AAEwFi2z_00052.jpg" title="r3.PNG" alt="wKioL1T6t2ygiag8AAEwFi2z_00052.jpg" />

    (7)g函數返回時結果儲存在eax中。回到f函數代碼繼續執行。其中leave指令相當於

        movq %rbp, %rsp

        popq %rbp

    程式執行後寄存器情況如下:

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/5A/37/wKioL1T6yeCR8m37AABhvAF94sQ270.jpg" title="r7.PNG" alt="wKioL1T6yeCR8m37AABhvAF94sQ270.jpg" />

    ret指令執行後rsp=0x7fffffffe548

    (8)完成f函數調用後,回到main函數執行addl $5, %eax語句。結果儲存在eax中。

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/5A/36/wKioL1T6uLPwsTMwAAEXKM8g8Cw505.jpg" title="r4.PNG" alt="wKioL1T6uLPwsTMwAAEXKM8g8Cw505.jpg" />

    (9)後面代碼是完成main函數返回,原理和一般函數調用相同,在此不在分析。

    

    總結:在我最初接觸電腦的時候,上機的機時還是很奢侈的東西,那時就給自己制定了學習方法:首先根據教材所教的知識,在頭腦中類比電腦會如何執行,假定課本上的例子都是正確的,推匯出機器應當給出什麼樣的結果,當有機會在電腦上操作時再進行驗證。現在看來,那時的思路是對的,但由於沒能堅持,今天的電腦水平還是一般。就本質而言,今天的電腦的確就是類比人的操作過程,程式員如何設計的程式,電腦就會不折不扣的執行。

本文出自 “StudyPark” 部落格,請務必保留此出處http://swordautumn.blog.51cto.com/1485402/1618288

電腦是如何工作的?

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.