機器級程式的小細節

劉小緒同學發表於2018-11-05

    隨著技術的逐漸發展,CPU 中電晶體的數量以每年 37% 的速度遞增,CPU 也從 16 位到了 32 位,現在已經到了 64 位,為了保證以前編譯的程式仍然能夠在最新的機器上使用,所以暫存器保留了原來的命名。

    比如一個 16 位的暫存器有自己的名字,當擴充套件成 32 位的時候,會保留原來 16 位暫存器的名字,並給整個 32 位暫存器取一個新的名字。如同“天生我材必有用”,每個暫存器都有它自己獨有的舞臺。

image

    最開始的 16 位稱之為“字(word)”,用於表示 16 位資料型別,擴充套件後的 32 位和 64 位分別稱為“雙字(double words)”和“四字(quad words)”。

    彙編程式碼最接近機器程式碼,它不像高階語言遮蔽了很多實現的細節,比如區分不同字長的資料,組合語言採用的方式是給彙編指令新增字尾(大多數情況下可以省略),即用字尾來指定運算元的大小,和暫存器一一對應。

image

    機器級程式使用的記憶體地址是虛擬地址,在機器級程式的眼裡,記憶體就是一個非常大的位元組陣列,而我們執行的程式就放在記憶體中。程式在機器眼裡就是一段位元組序列。

pushq   %rbx
movq    %rdx, %rbx
call    mult2
movq    %rax, (%rbx)
popq    %rbx
ret

    將這一段組合語言程式碼轉換成目標檔案,因為目標檔案時二進位制格式的,我們無法檢視,如果以 16 進製表示上述彙編程式碼,將是53 48 89 d3 e8 00 00 00 00 48 89 03 5b c3這樣的位元組序列。

    高階語言提供了物件導向的概念,C 語言也提供了陣列和結構體這樣的聚合資料型別,但是這所有的概念在機器級程式中都是不存在的,彙編程式碼不區分有符號或無符號整數,也不區分不同資料型別的指標,甚至連指標和整數都不進行區分。

    程式執行時是把指令序列放到記憶體中去,但是比如條件分支指令等情況會造成跳轉,使得指令地址變得不連續,有個 PC(程式計數器)就專職負責給出下一條指令的地址,這個 PC 的重要程度不言而喻。

    雖然我們覺得機器級程式程式設計已經很底層了,是上個世紀使用紙帶穿孔程式設計序的操作,但實際上機器級程式已經在硬體基礎上進行了一個層次的抽象,機器級程式的格式和行為是指令集體系結構或指令集架構來定義的。

    X86-64 的指令長度從 1 位元組到 15 位元組不等。不用多說,肯定是常用的指令所需要的位元組更少,而那些不常用或者運算元較多的指令就需要更多的位元組。

    設計指令的方式是從某個位置開始,可以將位元組唯一地解碼成機器指令。比如,只有指令pushq %rbx是以位元組值 53 開頭的。

    本以為第二章看起來就很枯燥了,沒想到第三章開起來更加枯燥,但是也越來越體會到抽象在電腦科學中的地位。

相關文章