計算機指令

在軟硬件接口中,CPU幫咱們作了什麼?

從硬件角度來看, CPU就是一個超大規模集成電路,經過電路實現了加法,乘法乃至各類各樣的處理邏輯。sass

從軟加工程師的角度來說,CPU就是一個執行各類計算機指令(Instruction Code)的邏輯機器。這裏的計算機指令,就比如一門CPU可以聽懂的語言,咱們把它叫作機器語言(Machine Language)函數

不一樣的CPU可以聽懂的語言不太同樣。好比咱們我的電腦用的Intel的CPU,蘋果手機用的是ARM的CPU。相似這樣兩種CPU各自支持的語言,就是兩組不一樣的計算機指令集(Instruction set)spa

一個計算機程序,不可能只有一條指令,而是由成千上萬條指令組成的。可是CPU裏不能一直放着全部指令,因此計算機程序平時是存儲在存儲器中的。這種指令存儲在存儲器裏面的計算機,咱們就叫作存儲程序型計算機操作系統

從編譯到彙編,代碼怎麼變成機器碼?

// test.c
int main()
{
    int a = 1;
    int b = 2;
    a = a + b;
}

要讓這段程序在一個Linux操做系統上跑起來,咱們須要把整個程序翻譯成一個彙編語言(ASM,Assembly Language)的程序,這個過程咱們通常叫編譯(Compile)成好彙編代碼。翻譯

針對彙編代碼,咱們能夠再用匯編器(Assembler)翻譯成機器碼(Machine Code)。這些機器碼由「0」和「1」組成的機器語言表示。這一條條機器碼,就是一條條的計算機指令。這樣一串串的16進制數字,就是咱們CPU可以真正認識的計算機指令設計

在一個Linux操做系統上,咱們能夠簡單地使用gcc和objdump這樣兩條命令,把對應的彙編代碼和機器碼都打印出來。code

[learning_log@localhost 桌面]$ gcc -g -c text.c
[learning_log@localhost 桌面]$ objdump -d -M intel -S text.o
text.o:     文件格式 elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
int main()
{
   0:    55                       push   rbp
   1:    48 89 e5                 mov    rbp,rsp
    int a = 1;
   4:    c7 45 fc 01 00 00 00     mov    DWORD PTR [rbp-0x4],0x1
    int b = 2;
   b:    c7 45 f8 02 00 00 00     mov    DWORD PTR [rbp-0x8],0x2
    a = a + b;
  12:    8b 45 f8                 mov    eax,DWORD PTR [rbp-0x8]
  15:    01 45 fc                 add    DWORD PTR [rbp-0x4],eax
}
  18:    5d                       pop    rbp
  19:    c3                       ret    

能夠看到左側一堆數字,這些就是一條條機器碼;右邊有一系列的push、mov、add、pop等,這些就是對應的彙編代碼。一行C語言代碼,有時候對應一條機器碼和彙編代碼,有時候則是對應兩條機器碼和彙編代碼。彙編代碼和機器碼之間是一一對應的。blog

從高級語言到彙編代碼,再到機器碼,就是一個平常開發程序,最終變成了CPU能夠執行的計算機指令的過程。接口

解析指令和機器碼

常見的指令能夠分爲五大類。內存

第一類是算術類指令。咱們的加減乘除,在CPU層面,都會變成一條條算術類指令。

第二類是數據傳輸類指令。給變量賦值,在內存裏讀寫數據,用的都是數據傳輸類指令。

第三類是邏輯類指令。邏輯上的與或非,都是這一類指令。

第四類是條件分支類指令。平常咱們寫的「if/else」,其實都是條件分支類指令。

最後一類是無條件跳轉指令。寫一些大一點的程序,咱們經常須要寫一些函數或者方法。再調用函數的時候,其實就是發起了一個無條件跳轉指令。

咱們說過,不一樣的CPU有不一樣的指令集,也就對應着不一樣的彙編語言和不一樣的機器碼。爲了方便你快速理解這個機器碼的計算方式,咱們選用最簡單的MIPS指令集,來看機器碼是如何生成的。

MIPS的指令是一個32位的整數,高6位叫操做碼(Opcode),也就是表明這條指令具體是一條什麼樣的指令,剩下的26位有三種格式,分別是R、I、J。

R指令是通常用來作算術和邏輯操做,裏面有讀取和寫入數據的寄存器的地址。若是是邏輯位移操做,後面還有位移操做的位移量,而最後的功能碼,則是在前面的操做碼不夠的時候,擴展操做碼錶示對應的具體指令的。

I指令,則一般是用來數據傳輸,條件分支,以及在運算的時候使用的並不是變量仍是常數的時候。這個時候,沒有了位移量和操做碼,也沒有了第三個寄存器,而是把這三部分直接合併成一個地址值或者常數。

J指令就是一個跳轉指令,高6位以外的26位都是一個跳轉後的地址。

add $t0,$s2,$s1

對應的MIPS指令裏的opcode是0,rs表明第一個寄存器s1的地址是17,rt表明第二個寄存器s2的地址是18,rd表明目標的臨時寄存器t0的地址,是8。由於不是位移操做,因此位移量是0.把這些數字拼在一塊兒,就變成了一個MIPS的加法指令。

爲了讀起來方便,咱們通常把對應的二進制數,用16進製表示,也就是0X02324020。這個數字也就是這條指令對應的機器碼。

若是想要對平常使用的Intel CPU的指令集有所瞭解,能夠參看《計算機組成與設計:軟/硬件藉口》第5版的2.17小節。

相關文章
相關標籤/搜索