『壹』 C語言如何編譯成可以直接在CPU運行的二進制碼
你編譯好的可執行文件就是二進制文件,包括機器碼指令和數據。Linux上生成的一般是ELF格式,帶文件頭和段記錄,你可以用strip什麼的去掉。
『貳』 什麼是代碼,代碼怎麼寫,怎樣寫入電腦
代碼就是程序員用開發工具所支持的語言寫出來的源文件,是一組由字元、符號或信號碼元以離散形式表示信息的明確的規則體系。代碼設計的原則包括唯一確定性、標准化和通用性、便於識別與記憶、力求短小與格式統一以及容易修改等。
簡單的說,你學會一門計算機語言然後就可以開始寫代碼了。寫代碼的過程叫做編程,編程是一項非常嚴謹的工作,一丁點錯誤都會導致你整個程序的崩潰。
寫好了代碼後,就可以用相應的編譯器寫入電腦了。編譯器能起到把源代碼編譯成能直接被計算機或虛擬機執行的目標代碼的作用。如果一切順利,經過編譯的代碼就生成了程序,就可以直接被電腦執行了。
(2)cpu怎麼編譯代碼擴展閱讀
大致說來,從人的易用性來分,電腦語言好用程度從難到易可以分為三類,一類是低級語言,如匯編語言、機器語言,一類是中級語言,如C語言,還有一類為高級語言。
一般來說,我們都是學習的高級語言。電腦語言的級別越高,越接近人類語言,但靈活性與效率也越低。
電腦本身是沒有思維能力的,它是嚴格按照人的預先設定指令工作的。這些指令都是用電腦語言按一定的語法規則寫成的。如果你寫出的程序有誤,電腦就不能正確工作。因此學習編寫電腦軟體,能培養我們的邏輯思維能力與嚴謹、周密的思維習慣。
如同任何一種語言,電腦語言也有自己的名詞,自己的基本詞彙,自己的語法結構。並且它們的語法結構大致相同。
『叄』 CPU晶元是用什麼語言編譯的
直接在電腦上編譯,「開始」-「運行」,輸入「cmd」,還要輸入masm xx.asm,就可以編譯了。
但是提示你要小心,因為這是在cpu上直接運轉,如果程序出錯,會直接毀壞cpu,要慎重的使用
『肆』 CPU是怎麼看懂代碼的
備註:這是我問答內容的一個精編版,增加了一些內容,所以和原內容略有不同。
去年底,有中國開發者已經開發出文言文編程語言,並在GitHub上摘得了5500星,在國內引起不小反響。這件事給普通人的印象是, 科技 發展日新月異,電腦CPU太厲害,都能讀懂文言文了!
CPU真的能看懂文言文代碼嗎?答案是CPU既看不懂文言文代碼,也看不懂英文代碼。
現在的CPU晶體管數量動輒幾十億個,結構非常復雜,但內部傳輸的信號只有兩種:高電壓和低電壓,分別代表數字信號「1」和「0」(也有相反的),因此CPU唯一能看懂的就是由「1」和「0」組成的代碼。
由於程序(代碼)存儲在電腦硬碟中時,也是「1」和「0」的形式,是否就意味著,只要程序存到硬碟中,CPU就能認識呢?
答案是CPU仍然看不懂這些程序,因為以「1」和「0」位模式存儲的程序和以「1」和「0」寫成的機器語言完全是兩回事,簡單說,兩者的區別類似於漢語書和英語書都用紙和油墨印製,但依然是兩種不同的語言,不會英語的依然看不懂英語書。
機器語言是CPU唯一能看懂的語言,也是第一代編程語言。
圖片說明:早期的計算機程序員使用機器語言編程,將用0和1數字編成的程序代碼打在紙帶或卡片上(打孔代表1,不打孔代表0),再將它通過紙帶機或卡片機輸入計算機,進行運算。
機器語言的最大特點是面向計算機硬體編程,簡單說就是程序員需要通曉計算機硬體知識,寫的程序要真實表示數據是如何被計算機操縱的。對程序員來說這就比較頭大,一方面不僅需要通曉計算機硬體知識,另一方面如果計算機使用了不同的硬體,那麼就得重新編程。
畢竟上得了「廳堂」(搞掂硬體)下得了「廚房」(玩得轉軟體),只有少數大神能做到,加上機器語言純用「0」和「1」序列組成,非常單調枯燥,不僅扼殺了編程的趣味,而且對視力也是一種考驗,稍微一眼花,看錯1或0的排列位置,就會製造一個大BUG。
於是,有一幫人開始琢磨了:能不能將計算機硬體從編程中分離出來,讓硬體知識小白也能編程?
最先開竅的是藍色巨人IBM,它在其System/360計算機中引入了ISA(Instruction Set Architecture)概念,將編程所需要了解的硬體信息從硬體中抽象出來,這樣編程人員就可以面向ISA編程。由於ISA是用來描述編程時用到的抽象機器(不是具體的電腦CPU),包括了一套指令集和一些寄存器,因此,程序員只要知道ISA,不需要了解具體的硬體知識,就可以編寫程序,在ISA相同的電腦上運行。
這樣一來,就出現了匯編語言,但匯編語言用符號寫成,還是不夠接地氣兒,於是高級語言就誕生了。高級語言的誕生,使程序員將精力從復雜的計算機結構轉移到要解決的問題,從而可以專心烹調程序大餐。
由此也可以看出,現在的程序員並不都是了解計算機硬體的,所以妹子們不要指望自己的程序員男朋友給你DIY電腦,或者電腦壞了,他能給你省下一筆修理費。他說不會修,那就是真的不會修。
自從高級語言出現後,人類開始了在編程語言上的放飛自我,經過數十年的發明創造,現在的高級編程語言已超過2500種,像比較知名的C++和Java等,都屬於高級語言。
但問題出現了,CPU能理解的機器語言還是那個機器語言,幾十年來沒有變化,讓它讀懂高級語言那是不可能的。
怎麼辦?
其實,早在高級語言出現之前的匯編語言時代,聰明的計算機研發人員就開發出了專門的程序,用來將匯編語言和高級語言翻譯成機器語言,其過程相當於將英語名著翻譯成漢語著作。
說白了,這種翻譯程序相當於人類中的翻譯家。
翻譯程序有兩種工作方法:編譯和解釋,相應的程序名稱是編譯器和解釋器。兩者的區別是,編譯是在執行前把整個源程序(高級語言程序)翻譯成目標程序(機器語言程序),而解釋是一次只翻譯和執行源程序中的一行。
打個形象的比方,解釋器相當於發布會的實時翻譯,演講的嘉賓說一句,實時翻譯馬上翻譯一句。編譯器則相當於著作翻譯家,整本翻譯完成後,再讓出版社印刷上市。
經過翻譯程序的努力,現在CPU能看懂程序員寫的程序了。當然,用開頭提到的文言文編程語言編寫的程序想要讓CPU看懂,還得多一道翻譯步驟,即要麼翻譯成Javascript,要麼翻譯成Python。多轉了一圈,不知道程序執行效率如何。
由於CPU不能直接理解用高級語言寫成的代碼,必須依賴翻譯程序翻譯成機器語言,因此翻譯程序可以極大地影響甚至決定處理器性能的發揮。如果沒有一個好的翻譯程序,那麼CPU的性能再強大,也好比茶壺裝的餃子,倒不出來。
正因為如此,谷歌在安卓4.4之後,拋棄了Dalvik虛擬機,改為ART,實際是將翻譯程序從解釋器切換到編譯器,發揮了晶元的性能,提高了程序運行效率。
現在,手機大廠包括華為、OPPO和vivo都開始重視編譯器開發,說到底就是為了發揮晶元性能,讓它不再成為倒不出餃子的茶壺。
最後總結一下,用翻譯程序把程序員編寫的程序翻譯成二進制代碼的機器語言後,CPU就能看懂代碼了,而且翻譯程序的優劣可以影響乃至決定CPU性能發揮。
圖片源自網路,版權歸圖片作者所有。
『伍』 簡述cpu實現分支的過程
可以看到在執行php時, 是一條一條去執行的
1.先判斷 $a 是否 等於 1
2.如果不等於1,為false, 就JMPZ 到第4條命令,去比較 $a 是否 等於2
如果等於1, echo "a is 1"; 然後 無條件跳轉 JMP 第9行 return 了
3.如果 $a 不等於2 ,即為false, 就JMPZ 到第8條命令, echo "a is x"
如果 $a 等於2,直接echo "a is 2", 然後執行 JMP 第9行 return 了
所以,php編寫的程序,對C函數來說,還是要一步的一步去執行的,關於具體php的分支實現,請點擊這里
如果這個文件被執行100次,有90次 $a=3, 那麼解釋器每次都要判斷 $a 是否等於1和 $a 是否等於2, 盡管第三個分支是滿足條件的,如果是C編寫的程序, CPU會針對某種策略挑選一個分支來執行, 對應上面的分支來說,CPU會直接取出第三個分支的指令,然後執行。
從486開始,CPU開始具備流水線這個特性,指令流水線由5,6個不同功能的工作單元組成,將一個x86指令也拆分成5,6個步驟,分別送往不同的工作單元,來達到同時執行多個指令的目的,現在的CPU支持30級的流水線,也就意味著流水線上有30個工作單元,對應的X86指令也拆分成30個步驟。
註:CPU執行的是二進制數據,代碼經過匯編編譯後,生成一條條二進制指令
例如 int a=1; 對應的匯編是mov $1, %eax; 對應的機器碼可能是00011100011
在執行文件時,根據局部性原理,想關的指令都要載入到CPU緩存中,
一般一條指令的完成 分四個步驟:
1.取指令
2.翻譯指令 (看是賦值,還是計算,從內存什麼地方取數據)
3.執行指令
4.寫指令結果 (要麼寫回內存,要麼寫到寄存器)
取指令翻譯指令執行指令寫指令結果
命令1 命令1
命令2
取指令單元取出指令1後,翻譯指令單元開始 翻譯指令1時,取指令單元可 取出指令2了
如果CPU不這么做,等到指令1完成上面四個步驟後,指令2才開始進行,那效率太低了
流水化中的單元分的更詳細, 更多的指令可以並行處理,但速度不見得快,因為有分支的出現,如果沒有命中第一個分支,後面的指令將作廢, 需要清空後面所有的指令, 然後中載命中地址的指令,再運行
在有5個分支的情況下,若採取隨機挑選一個分支 執行的話,每次賭該分支命中的概率只有五分之一, 於是CPU分支預測功能就出現了。
分支預測分靜態和動態
靜態分支預測:由編譯器決定哪個分支可能被CPU命中,一般是第一個分支,即 if 後面的邏輯,而不是後面else的邏輯
動態分支預測:在CPU硬體中開辟一塊緩存,專門記錄每個分支最近幾次的命中情況,然後做出預測,顯然這種方法能及時調整策略,有更好的遠詹性,但CPU壓力會大些,不過還好。分支地址只有在流水線指令執行階段才能計算出來,為了避免等待,需要在解碼階段進行預測
Two-Level分支預測方法使用了兩種數據結構,一種是BHR(Branch History Register);而另一種是PHT(Pattern History Table)。其中BHR由k位組成(可理解為記錄K次某個分支的執行結果),用來記錄每一條轉移指令的歷史狀態,而PHT表含有2k個Entry組成,而每一個Entry由兩位Saturating Counter組成。BHR和PHT的關系如圖3‑10所示。
假設分支預測單元在使用Two-Level分支預測方法時,設置了一個PBHT表(Per-address Branch History Table)存放不同指令所對應的BHR。在PBHT表中所有BHR的初始值為全1,而在PHT表中所有Entry的初始值值為0b11。BHR在PBHT表中的使用方法與替換機制與Cache類似。
當分支預測單元分析預測轉移指令B的執行時,將首先從PBHT中獲得與轉移指令B對應的BHR,此時BHR為全1,因此CPU將從PHT的第11…11個Entry中獲得預測結果0b11,即Strongly Taken。轉移指令B執行完畢後,將實際執行結果Rc更新到BHR寄存器中,並同時更新PHT中對應的Entry。
當CPU再次預測轉移指令B的執行時,仍將根據BHR索引PHT表,並從對應Entry中獲得預測結果。而當指令B再次執行完畢後,將繼續更新BHR和PHT表中對應的Entry。當轉移指令的執行結果具有某種規律(Pattern)時,使用這種方法可以有效提高預測精度。如果轉移指令B的實際執行結果為001001001….001,而且k等於4時,CPU將以0010-0100-1001這樣的循環訪問BHR,因此CPU將分別從PHT表中的第0010、0100和1001個Entry中獲得准確的預測結果。
由以上描述可以發現,Two-Level分支預測法具有學習功能,並可以根據轉移指令的歷史記錄產生的模式,在PHT表中查找預測結果。該演算法由T.Y. Yeh and Y.N. Patt在1991年提出,並在高性能處理器中得到了大規模應用。
Two-Level分支預測法具有許多變種。目前x86處理器主要使用「Local Branch Prediction」和「Global Branch Prediction」兩種演算法。
『陸』 C#源代碼編譯成為本地代碼的編譯過程
很有興趣的話,可以去閱讀下JeffreyRitchie的《ClrviaC#》,目前出到第三版,英文好的話強烈推薦看英文版的,而且我有該電子書和實體書。
下面講下我的理解:大致上不會出什麼差錯的,細節部分你可以參照上面的書籍!
1.首先,c#源碼經過c#編譯器被編譯成託管模塊(IL中間代碼、元數據(Metadata))
2.然後,使用C#編譯器以及程序集鏈接器(AssemblyLinker----AL.exe)將上述託管模塊以及項目的資源文件Combine(整合)成一個程序集(Assembly)
上述程序集就是你所看到的exe文件或者dll文件等等,程序集中包含了manifest描述文件,是該程序集內容以及關系的一個清單,具體的內容你可以參見JR的書跟Java中的類似!
雙擊該exe運行的時候:
3.最後,運行時,CLR裝載對應的程序集,使用內部的三個即時編譯器(常用的為JIT),再去根據本機的環境去進行相應的優化(針對CPU優化等等),即時的翻譯成本地機器指令去執行。
還有一個本地化代碼生成工具,NGen.exe~~
這個最好能去看看那本JR的神作!細節不是我三言兩語能講清的~~
『柒』 源碼怎麼編譯
使用編譯器如VC++6.0,VC++2008