彙編指令集與cpu指令集是什麼關係?

它們是對應的嗎? 為什麼高級程序編譯時會先轉換為彙編指令然後再轉成機器碼?


彙編是助記符,因為人要自己去記機器碼實在太傷了,所以用一些稍微好看的的符號記一下。這裡面有這麼幾個point:

1. 一個彙編指令會對應多種不同的機器碼,比如MOV指令,實際編碼的時候是分8位 16位 32位 64位,是寄存器-&>寄存器 內存-&> 寄存器 寄存器-&>內存, 內存又要考慮各種定址方式,變成機器碼的時候都有出入,所以彙編實際上還有一定程度的抽象,把一組含義接近的機器碼統一成一個指令

2. 不是所有機器碼都能找到彙編何其對應的,因為存在一個指令邊界的問題:每條指令不只是一個byte,所以使用機器碼的時候,完全可以jmp到別的指令的中間開始執行,這種情況要用彙編來表示是很困難的。

3. 具體到編譯器,把生成編譯器彙編代碼 彙編器生成機器碼兩者分開是有好處的,因為這樣你的編譯器就不用處理彙編器那一坨複雜的編碼的邏輯了

4. 當然完全可以編譯器不產生彙編,直接生成機器碼,印象中tcc就是這麼乾的


可能用RISC的指令集解釋更清楚一點。

比如常年用來教學(以及部分機頂盒/路由器)使用的MIPS指令集,其指令為定長。比如你是32位,MIPS32的指令集每條指令都是32bit的。

那麼會出現很多問題。比如你不能直接產生一個32bit的立即數賦值給某寄存器。但是人去編寫/高級語言生成的時候,很容易出現類似的指令。

比如最常見的

li rx imm32

意味將立即數imm32賦值給rx

這不是一條MIPS的cpu指令,其長度超過了32bit,但是確實一條MIPS彙編指令,因為彙編器會將其拓展成

li rx hi_16
sll rx rx 0
addiu rx lo_16

三條cpu指令,每條都是32bit長。分別意為

將hi_16位賦值給rx,將rx左移16位,將rx加上lo_16。

所以還是有區別的(但是區別非常非常小,你也可以手寫這三條指令來完成同樣的功能)。


這裡面其實不止2層,我就按3層來講講。

首先,實現才是最重要的,才是切實存在的。標準和實現本身是有間隔的,不論它們的間隔有多小。

那麼在這個問題里哪些是實現哪些是標準呢:CPU本身就是實現,CPU指令集實際上是標準。

我先談一下這裡面涉及的幾個詞,再說一下它們是怎麼關聯起來的。

話說在前頭,這裡不存在一個中央機構,裁決這些詞的哪些用法是對的哪些用法是錯的,所以我只是根據自己對人們運用這些辭彙的習慣的理解寫下這些文字。

彙編指令 它是彙編編程中的一條命令,它的含義是觸發CPU的一次狀態遷移。

彙編指令集 我的理解是,它是彙編編程中可用指令的集合。

彙編編程 如果CPU的指令的編碼規則不太複雜,那麼通常可以做出這樣一種工具:我們用一些文字性的內容表示CPU機器碼的內容,然後這種工具匹配出這些內容有哪些要素,根據這些要素所代表的數字通過簡單的加減乘除實際換成CPU需要的數字序列。那麼,編寫這種工具的輸入就是所謂的彙編編程。

CPU指令集 它是人們對CPU功能的一種低層次的抽象,和CPU運作中使用的數字序列「幾乎」存在一種對應關係。

CPU機器碼 CPU使用的數字序列。CPU從存儲器中試圖讀出一串序列來完成一次狀態遷移。

所以我說的3層是指這3層:機器碼、CPU指令集還有彙編編程。以下將CPU指令集簡稱指令集。

彙編編程實際上最終面對的是機器碼,那麼為什麼要涉及指令集這個玩意呢……因為指令集它不是數字序列。除了算術學家,沒人想對著一堆數字思考。數學家喜歡符號。學生可能覺得符號望而生畏很難適應,那是因為他暫時還沒意識到直接對著數字想那是有多困難。

當我們開始起名字的時候,數字就不單純是數字了,所以我說指令集是一種抽象是一種理想。

我們在說彙編指令的時候提到CPU需要的是數字序列也就是機器碼,這個轉換過程叫彙編,我理解成「匯總、編輯」,匯總之前實際還涉及一些替換以及四則運算,這個我們也說過了。匯總的意思是,我們編寫的這些CPU機器碼的文字性表示也許分散在幾個不同的地方,所以我們需要匯總起來。編輯的意思是,我們會在彙編指令之間(又或者是末尾或開頭)插入一些標記,在轉換成機器碼之前它們需要適時換成此處的數字前總共有多少個數字,我們有一些彙編指令會需要這個數量。

那麼我們為這個轉換,也就說彙編,編寫的工具叫做彙編器。彙編器的作者,他也不想只對著一堆數字思考。他參照指令集來考慮,實現這樣一套工具。有了彙編器,我們就可以做彙編編程了,當然是照著這個彙編器的規則來編程。

那麼,重點來了,為什麼高級語言編譯器要把源代碼轉成彙編指令呢。對於編譯器作者有很多個理由可以這麼做:

  1. 他也不想對著數字思考,反正彙編器作者已經受了一次罪了他就可以輕鬆了
  2. 有幾個機器碼形式不同的CPU需要他的編譯器支持,他覺得這樣可以省點功夫
  3. 只有一個CPU需要支持,但他怕領導未來讓他支持其他CPU,所以先留點後路
  4. 他很同情他未來的同事,想著如果未來同事要支持不同的CPU,可以按照他的工作結果改,能輕鬆一些
  5. 領導沒限制他這麼做,他愛這麼做就這麼幹了
  6. 領導叫他別這麼做,他就愛跟領導對著干

那麼我們也不能都怪罪幹活的人,也許問題出在管理者:

  1. 領導覺得這麼干挺好,就該這麼干
  2. 領導的領導要求這麼干

我想再強調一次,這個領域沒有一個中央機構威脅你這麼干是對的那麼干是錯的。

我們平時談文法,帶屬性的上下文無關語言,談AST樹……沒錯,這些知識挺有幫助的。

但是如果你只為自己工作並且你能做到,你可以寫一堆麵條代碼搞出一個功能完善的高級語言編譯器,只有你自己清楚它是怎麼工作的——也許你自己也不知道。先別笑,發表了一些很聰明的量子力學公式的物理學家狄拉克就說過,他的公式比他聰明。有時候你的程序在某些方面就是比你聰明一點。

也許有人會提出抗議:你寫麵條代碼做編譯器,以後怎麼維護啊?

去你的,又不是為你幹活,不喜歡你自己寫一個啊?


彙編和機器碼的區別就跟"1"和0x1的區別一樣小


基本對應。彙編還有一些方便的偽指令。彙編還幫你計算一些地址 比如 JMP FOO。一般開發工具都有一個彙編器。為了重用,一般編譯器就生成彙編了。也有反過來,編譯器帶彙編功能,然後彙編器只是調用編譯器的某個庫。比如LLVM和LLVM-MC的關係


彙編是離機器碼最近的一個人類可閱讀可編寫的語言形式。

機器(CPU)為了運算速度,被設計成只能閱讀010101這樣的文字的東西。

而人類不可能用0 和 1 ,來寫程序,閱讀和理解和修改起來太費勁了,效率太低。

所以最開始就有了彙編語言,人類用彙編語言來寫人類看得懂的程序,例如:MOV AH,15

之後「編譯器」這個程序會把人類編寫的程序,翻譯成CPU能理解的010101.........

通過編程語言建立起人類和CPU之間的翻譯工作。

估計你以後會問為什麼會用C語言編程很簡單,C比彙編更加效率。


因為彙編指令對應的機器碼實在難記,彙編指令就是助記符,想像一下,全部用機器碼編程得多困難...地址的高8位低8位 還要換順序什麼的....有了彙編指令就簡單好多了,再有了更高級的語言後,就比彙編方便多了。

彙編指令對應的有機器碼 。


推薦閱讀:

Hash時取模一定要模質數嗎?
易語言有哪些優點?
編程用什麼筆記本比較好?
為什麼有人熱衷於吵哪個計算機語言好?
如果編程語言是從象語素文字而非表音文字設計,什麼會不同?

TAG:中央處理器CPU | 編程 | 計算機科學 | CPU指令集 | 計算機工程CE |