原文鏈接:https://chai2010.cn/advanced-go-programming-book/ch3-asm/ch3-02-arch.html
匯編語(yǔ)言是直面計(jì)算機(jī)的編程語(yǔ)言,因此理解計(jì)算機(jī)結(jié)構(gòu)是掌握匯編語(yǔ)言的前提。當(dāng)前流行的計(jì)算機(jī)基本采用的是馮·諾伊曼計(jì)算機(jī)體系結(jié)構(gòu)(在某些特殊領(lǐng)域還有哈佛體系架構(gòu))。馮·諾依曼結(jié)構(gòu)也稱為普林斯頓結(jié)構(gòu),采用的是一種將程序指令和數(shù)據(jù)存儲(chǔ)在一起的存儲(chǔ)結(jié)構(gòu)。馮·諾伊曼計(jì)算機(jī)中的指令和數(shù)據(jù)存儲(chǔ)器其實(shí)指的是計(jì)算機(jī)中的內(nèi)存,然后在配合 CPU 處理器就組成了一個(gè)最簡(jiǎn)單的計(jì)算機(jī)了。
匯編語(yǔ)言其實(shí)是一種非常簡(jiǎn)單的編程語(yǔ)言,因?yàn)樗嫦虻挠?jì)算機(jī)模型就是非常簡(jiǎn)單的。讓人覺(jué)得匯編語(yǔ)言難學(xué)主要有幾個(gè)原因:不同類型的 CPU 都有自己的一套指令;即使是相同的 CPU,32 位和 64 位的運(yùn)行模式依然會(huì)有差異;不同的匯編工具同樣有自己特有的匯編指令;不同的操作系統(tǒng)和高級(jí)編程語(yǔ)言和底層匯編的調(diào)用規(guī)范并不相同。本節(jié)將描述幾個(gè)有趣的匯編語(yǔ)言模型,最后精簡(jiǎn)出一個(gè)適用于 AMD64 架構(gòu)的精簡(jiǎn)指令集,以便于 Go 匯編語(yǔ)言的學(xué)習(xí)。
圖靈機(jī)是由圖靈提出的一種抽象計(jì)算模型。機(jī)器有一條無(wú)限長(zhǎng)的紙帶,紙帶分成了一個(gè)一個(gè)的小方格,每個(gè)方格有不同的顏色,這類似于計(jì)算機(jī)中的內(nèi)存。同時(shí)機(jī)器有一個(gè)探頭在紙帶上移來(lái)移去,類似于通過(guò)內(nèi)存地址來(lái)讀寫內(nèi)存上的數(shù)據(jù)。機(jī)器頭有一組內(nèi)部計(jì)算狀態(tài),還有一些固定的程序(更像一個(gè)哈佛結(jié)構(gòu))。在每個(gè)時(shí)刻,機(jī)器頭都要從當(dāng)前紙帶上讀入一個(gè)方格信息,然后根據(jù)自己的內(nèi)部狀態(tài)和當(dāng)前要執(zhí)行的程序指令將信息輸出到紙帶方格上,同時(shí)更新自己的內(nèi)部狀態(tài)并進(jìn)行移動(dòng)。
圖靈機(jī)雖然不容易編程,但是非常容易理解。有一種極小化的 BrainFuck 計(jì)算機(jī)語(yǔ)言,它的工作模式和圖靈機(jī)非常相似。BrainFuck 由 Urban Müller 在 1993 年創(chuàng)建的,簡(jiǎn)稱為 BF 語(yǔ)言。Müller 最初的設(shè)計(jì)目標(biāo)是建立一種簡(jiǎn)單的、可以用最小的編譯器來(lái)實(shí)現(xiàn)的、符合圖靈完全思想的編程語(yǔ)言。這種語(yǔ)言由八種狀態(tài)構(gòu)成,早期為 Amiga 機(jī)器編寫的編譯器(第二版)只有 240 個(gè)字節(jié)大??!
就象它的名字所暗示的,brainfuck 程序很難讀懂。盡管如此,brainfuck 圖靈機(jī)一樣可以完成任何計(jì)算任務(wù)。雖然 brainfuck 的計(jì)算方式如此與眾不同,但它確實(shí)能夠正確運(yùn)行。這種語(yǔ)言基于一個(gè)簡(jiǎn)單的機(jī)器模型,除了指令,這個(gè)機(jī)器還包括:一個(gè)以字節(jié)為單位、被初始化為零的數(shù)組、一個(gè)指向該數(shù)組的指針(初始時(shí)指向數(shù)組的第一個(gè)字節(jié))、以及用于輸入輸出的兩個(gè)字節(jié)流。這是一種按照?qǐng)D靈完備的語(yǔ)言,它的主要設(shè)計(jì)思路是:用最小的概念實(shí)現(xiàn)一種 “簡(jiǎn)單” 的語(yǔ)言。BrainFuck 語(yǔ)言只有八種符號(hào),所有的操作都由這八種符號(hào)的組合來(lái)完成。
下面是這八種狀態(tài)的描述,其中每個(gè)狀態(tài)由一個(gè)字符標(biāo)識(shí):
字符 | C 語(yǔ)言類比 | 含義 |
---|---|---|
>
|
++ptr;
|
指針加一 |
<
|
--ptr;
|
指針減一 |
+
|
++*ptr;
|
指針指向的字節(jié)的值加一 |
-
|
--*ptr;
|
指針指向的字節(jié)的值減一 |
.
|
putchar(*ptr);
|
輸出指針指向的單元內(nèi)容(ASCⅡ 碼) |
,
|
*ptr = getch();
|
輸入內(nèi)容到指針指向的單元(ASCⅡ 碼) |
[
|
while(*ptr) {}
|
如果指針指向的單元值為零,向后跳轉(zhuǎn)到對(duì)應(yīng)的 ] 指令的次一指令處 |
]
|
如果指針指向的單元值不為零,向前跳轉(zhuǎn)到對(duì)應(yīng)的 [ 指令的次一指令處 |
下面是一個(gè) brainfuck 程序,向標(biāo)準(zhǔn)輸出打印 "hi" 字符串:
++++++++++[>++++++++++<-]>++++.+.
理論上我們可以將 BF 語(yǔ)言當(dāng)作目標(biāo)機(jī)器語(yǔ)言,將其它高級(jí)語(yǔ)言編譯為 BF 語(yǔ)言后就可以在 BF 機(jī)器上運(yùn)行了。
《人力資源機(jī)器》(Human Resource Machine)是一款設(shè)計(jì)精良匯編語(yǔ)言編程游戲。在游戲中,玩家扮演一個(gè)職員角色,來(lái)模擬人力資源機(jī)器的運(yùn)行。通過(guò)完成上司給的每一份任務(wù)來(lái)實(shí)現(xiàn)晉升的目標(biāo),完成任務(wù)的途徑就是用游戲提供的 11 個(gè)機(jī)器指令編寫正確的匯編程序,最終得到正確的輸出結(jié)果。人力資源機(jī)器的匯編語(yǔ)言可以認(rèn)為是跨平臺(tái)、跨操作系統(tǒng)的通用的匯編語(yǔ)言,因?yàn)樵?macOS、Windows、Linux 和 iOS 上該游戲的玩法都是完全一致的。
人力資源機(jī)器的機(jī)器模型非常簡(jiǎn)單:INBOX
命令對(duì)應(yīng)輸入設(shè)備,OUTBOX
對(duì)應(yīng)輸出設(shè)備,玩家小人對(duì)應(yīng)一個(gè)寄存器,臨時(shí)存放數(shù)據(jù)的地板對(duì)應(yīng)內(nèi)存,然后是數(shù)據(jù)傳輸、加減、跳轉(zhuǎn)等基本的指令。總共有 11 個(gè)機(jī)器指令:
名稱 | 解釋 |
---|---|
INBOX
|
從輸入通道取一個(gè)整數(shù)數(shù)據(jù),放到手中 (寄存器) |
OUTBOX
|
將手中(寄存器)的數(shù)據(jù)放到輸出通道,然后手中將沒(méi)有數(shù)據(jù)(此時(shí)有些指令不能運(yùn)行) |
COPYFROM
|
將地板上某個(gè)編號(hào)的格子中的數(shù)據(jù)復(fù)制到手中(手中之前的數(shù)據(jù)作廢),地板格子必須有數(shù)據(jù) |
COPYTO
|
將手中(寄存器)的數(shù)據(jù)復(fù)制到地板上某個(gè)編號(hào)的格子中,手中的數(shù)據(jù)不變 |
ADD
|
將手中(寄存器)的數(shù)據(jù)和某個(gè)編號(hào)對(duì)應(yīng)的地板格子的數(shù)據(jù)相加,新數(shù)據(jù)放到手中(手中之前的數(shù)據(jù)作廢) |
SUB
|
將手中(寄存器)的數(shù)據(jù)和某個(gè)編號(hào)對(duì)應(yīng)的地板格子的數(shù)據(jù)相減,新數(shù)據(jù)放到手中(手中之前的數(shù)據(jù)作廢) |
BUMP+
|
自加一 |
BUMP-
|
自減一 |
JUMP
|
跳轉(zhuǎn) |
JUMP =0
|
為零條件跳轉(zhuǎn) |
JUMP <0
|
為負(fù)條件跳轉(zhuǎn) |
除了機(jī)器指令外,游戲中有些環(huán)節(jié)還提供類似寄存器的場(chǎng)所,用于存放臨時(shí)的數(shù)據(jù)。人力資源機(jī)器游戲的機(jī)器指令主要分為以下幾類:
INBOX
?/?OUTBOX
?): 輸入后手中將只有 1 份新拿到的數(shù)據(jù), 輸出后手中將沒(méi)有數(shù)據(jù)。COPYFROM
?/?COPYTO
?): 主要用于僅有的 1 個(gè)寄存器(手中)和內(nèi)存之間的數(shù)據(jù)傳輸,傳輸時(shí)要確保源數(shù)據(jù)是有效的ADD
?/?SUB
?/?BUMP+
?/?BUMP-
?)主流的處理器也有類似的指令。除了基本的算術(shù)和邏輯運(yùn)算指令外,再配合有條件跳轉(zhuǎn)指令就可以實(shí)現(xiàn)分支、循環(huán)等常見(jiàn)控制流結(jié)構(gòu)了。
下圖是某一層的任務(wù):將輸入數(shù)據(jù)的 0 剔除,非 0 的數(shù)據(jù)依次輸出,右邊部分是解決方案。
圖 3-1 人力資源機(jī)器
整個(gè)程序只有一個(gè)輸入指令、一個(gè)輸出指令和兩個(gè)跳轉(zhuǎn)指令共四個(gè)指令:
LOOP:
INBOX
JUMP-if-zero LOOP
OUTBOX
JUMP LOOP
首先通過(guò) INBOX
指令讀取一個(gè)數(shù)據(jù)包;然后判斷包裹的數(shù)據(jù)是否為 0
,如果是 0
的話就跳轉(zhuǎn)到開(kāi)頭繼續(xù)讀取下一個(gè)數(shù)據(jù)包;否則將輸出數(shù)據(jù)包,然后再跳轉(zhuǎn)到開(kāi)頭。以此循環(huán)無(wú)休止地處理數(shù)據(jù)包裹,直到任務(wù)完成晉升到更高一級(jí)的崗位,然后處理類似的但更復(fù)雜的任務(wù)。
X86 其實(shí)是是 80X86 的簡(jiǎn)稱(后面三個(gè)字母),包括 Intel 8086、80286、80386 以及 80486 等指令集合,因此其架構(gòu)被稱為 x86 架構(gòu)。x86-64 是 AMD 公司于 1999 年設(shè)計(jì)的 x86 架構(gòu)的 64 位拓展,向后兼容于 16 位及 32 位的 x86 架構(gòu)。X86-64 目前正式名稱為 AMD64,也就是 Go 語(yǔ)言中 GOARCH 環(huán)境變量指定的 AMD64。如果沒(méi)有特殊說(shuō)明的話,本章中的匯編程序都是針對(duì) 64 位的 X86-64 環(huán)境。
在使用匯編語(yǔ)言之前必須要了解對(duì)應(yīng)的 CPU 體系結(jié)構(gòu)。下面是 X86/AMD 架構(gòu)圖:
圖 3-2 AMD64 架構(gòu)
左邊是內(nèi)存部分是常見(jiàn)的內(nèi)存布局。其中 text 一般對(duì)應(yīng)代碼段,用于存儲(chǔ)要執(zhí)行指令數(shù)據(jù),代碼段一般是只讀的。然后是 rodata 和 data 數(shù)據(jù)段,數(shù)據(jù)段一般用于存放全局的數(shù)據(jù),其中 rodata 是只讀的數(shù)據(jù)段。而 heap 段則用于管理動(dòng)態(tài)的數(shù)據(jù),stack 段用于管理每個(gè)函數(shù)調(diào)用時(shí)相關(guān)的數(shù)據(jù)。在匯編語(yǔ)言中一般重點(diǎn)關(guān)注 text 代碼段和 data 數(shù)據(jù)段,因此 Go 匯編語(yǔ)言中專門提供了對(duì)應(yīng) TEXT 和 DATA 命令用于定義代碼和數(shù)據(jù)。
中間是 X86 提供的寄存器。寄存器是 CPU 中最重要的資源,每個(gè)要處理的內(nèi)存數(shù)據(jù)原則上需要先放到寄存器中才能由 CPU 處理,同時(shí)寄存器中處理完的結(jié)果需要再存入內(nèi)存。X86 中除了狀態(tài)寄存器 FLAGS 和指令寄存器 IP 兩個(gè)特殊的寄存器外,還有 AX、BX、CX、DX、SI、DI、BP、SP 幾個(gè)通用寄存器。在 X86-64 中又增加了八個(gè)以 R8-R15 方式命名的通用寄存器。因?yàn)闅v史的原因 R0-R7 并不是通用寄存器,它們只是 X87 開(kāi)始引入的 MMX 指令專有的寄存器。在通用寄存器中
BP 和 SP 是兩個(gè)比較特殊的寄存器:其中 BP 用于記錄當(dāng)前函數(shù)幀的開(kāi)始位置,和函數(shù)調(diào)用相關(guān)的指令會(huì)隱式地影響 BP 的值;SP 則對(duì)應(yīng)當(dāng)前棧指針的位置,和棧相關(guān)的指令會(huì)隱式地影響 SP 的值;而某些調(diào)試工具需要 BP 寄存器才能正常工作。
右邊是 X86 的指令集。CPU 是由指令和寄存器組成,指令是每個(gè) CPU 內(nèi)置的算法,指令處理的對(duì)象就是全部的寄存器和內(nèi)存。我們可以將每個(gè)指令看作是 CPU 內(nèi)置標(biāo)準(zhǔn)庫(kù)中提供的一個(gè)個(gè)函數(shù),然后基于這些函數(shù)構(gòu)造更復(fù)雜的程序的過(guò)程就是用匯編語(yǔ)言編程的過(guò)程。
Go 匯編為了簡(jiǎn)化匯編代碼的編寫,引入了 PC、FP、SP、SB 四個(gè)偽寄存器。四個(gè)偽寄存器加其它的通用寄存器就是 Go 匯編語(yǔ)言對(duì) CPU 的重新抽象,該抽象的結(jié)構(gòu)也適用于其它非 X86 類型的體系結(jié)構(gòu)。
四個(gè)偽寄存器和 X86/AMD64 的內(nèi)存和寄存器的相互關(guān)系如下圖:
圖 3-3 Go 匯編的偽寄存器
在 AMD64 環(huán)境,偽 PC 寄存器其實(shí)是 IP 指令計(jì)數(shù)器寄存器的別名。偽 FP 寄存器對(duì)應(yīng)的是函數(shù)的幀指針,一般用來(lái)訪問(wèn)函數(shù)的參數(shù)和返回值。偽 SP 棧指針對(duì)應(yīng)的是當(dāng)前函數(shù)棧幀的底部(不包括參數(shù)和返回值部分),一般用于定位局部變量。偽 SP 是一個(gè)比較特殊的寄存器,因?yàn)檫€存在一個(gè)同名的 SP 真寄存器。真 SP 寄存器對(duì)應(yīng)的是棧的頂部,一般用于定位調(diào)用其它函數(shù)的參數(shù)和返回值。
當(dāng)需要區(qū)分偽寄存器和真寄存器的時(shí)候只需要記住一點(diǎn):偽寄存器一般需要一個(gè)標(biāo)識(shí)符和偏移量為前綴,如果沒(méi)有標(biāo)識(shí)符前綴則是真寄存器。比如 (SP)
、+8(SP)
沒(méi)有標(biāo)識(shí)符前綴為真 SP 寄存器,而 a(SP)
、b+8(SP)
有標(biāo)識(shí)符為前綴表示偽寄存器。
很多匯編語(yǔ)言的教程都會(huì)強(qiáng)調(diào)匯編語(yǔ)言是不可移植的。嚴(yán)格來(lái)說(shuō)匯編語(yǔ)言是在不同的 CPU 類型、或不同的操作系統(tǒng)環(huán)境、或不同的匯編工具鏈下是不可移植的,而在同一種 CPU 中運(yùn)行的機(jī)器指令是完全一樣的。匯編語(yǔ)言這種不可移植性正是其普及的一個(gè)極大的障礙。雖然 CPU 指令集的差異是導(dǎo)致不好移植的較大因素,但是匯編語(yǔ)言的相關(guān)工具鏈對(duì)此也有不可推卸的責(zé)任。而源自 Plan9 的 Go 匯編語(yǔ)言對(duì)此做了一定的改進(jìn):首先 Go 匯編語(yǔ)言在相同 CPU 架構(gòu)上是完全一致的,也就是屏蔽了操作系統(tǒng)的差異;同時(shí) Go
匯編語(yǔ)言將一些基礎(chǔ)并且類似的指令抽象為相同名字的偽指令,從而減少不同 CPU 架構(gòu)下匯編代碼的差異(寄存器名字和數(shù)量的差異是一直存在的)。本節(jié)的目的也是找出一個(gè)較小的精簡(jiǎn)指令集,以簡(jiǎn)化 Go 匯編語(yǔ)言的學(xué)習(xí)。
X86 是一個(gè)極其復(fù)雜的系統(tǒng),有人統(tǒng)計(jì) x86-64 中指令有將近一千個(gè)之多。不僅僅如此,X86 中的很多單個(gè)指令的功能也非常強(qiáng)大,比如有論文證明了僅僅一個(gè) MOV
指令就可以構(gòu)成一個(gè)圖靈完備的系統(tǒng)。以上這是兩種極端情況,太多的指令和太少的指令都不利于匯編程序的編寫,但是也從側(cè)面體現(xiàn)了 MOV
指令的重要性。
通用的基礎(chǔ)機(jī)器指令大概可以分為數(shù)據(jù)傳輸指令、算術(shù)運(yùn)算和邏輯運(yùn)算指令、控制流指令和其它指令等幾類。因此我們可以嘗試精簡(jiǎn)出一個(gè) X86-64 指令集,以便于 Go 匯編語(yǔ)言的學(xué)習(xí)。
因此我們先看看重要的 MOV 指令。其中 MOV 指令可以用于將字面值移動(dòng)到寄存器、字面值移到內(nèi)存、寄存器之間的數(shù)據(jù)傳輸、寄存器和內(nèi)存之間的數(shù)據(jù)傳輸。需要注意的是,MOV 傳輸指令的內(nèi)存操作數(shù)只能有一個(gè),可以通過(guò)某個(gè)臨時(shí)寄存器達(dá)到類似目的。最簡(jiǎn)單的是忽略符號(hào)位的數(shù)據(jù)傳輸操作,386 和 AMD64 指令一樣,不同的 1、2、4 和 8 字節(jié)寬度有不同的指令:
Data Type | 386/AMD64 | Comment |
---|---|---|
[1]byte
|
MOVB | B => Byte |
[2]byte
|
MOVW | W => Word |
[4]byte
|
MOVL | L => Long |
[8]byte
|
MOVQ | Q => Quadword |
MOV 指令它不僅僅用于在寄存器和內(nèi)存之間傳輸數(shù)據(jù),而且還可以用于處理數(shù)據(jù)的擴(kuò)展和截?cái)嗖僮?。?dāng)數(shù)據(jù)寬度和寄存器的寬度不同又需要處理符號(hào)位時(shí),386 和 AMD64 有各自不同的指令:
Data Type | 386 | AMD64 | Comment |
---|---|---|---|
int8
|
MOVBLSX | MOVBQSX | sign extend |
uint8
|
MOVBLZX | MOVBQZX | zero extend |
int16
|
MOVWLSX | MOVWQSX | sign extend |
uint16
|
MOVWLZX | MOVWQZX | zero extend |
比如當(dāng)需要將一個(gè) int64
類型的數(shù)據(jù)轉(zhuǎn)為 bool
類型時(shí),則需要使用 MOVBQZX
指令處理。
基礎(chǔ)算術(shù)指令有 ADD
、SUB
、MUL
、DIV
等指令。其中 ADD
、SUB
、MUL
、DIV
用于加、減、乘、除運(yùn)算,最終結(jié)果存入目標(biāo)寄存器?;A(chǔ)的邏輯運(yùn)算指令有 AND
、OR
和 NOT
等幾個(gè)指令,對(duì)應(yīng)邏輯與、或和取反等幾個(gè)指令。
名稱 | 解釋 |
---|---|
ADD
|
加法 |
SUB
|
減法 |
MUL
|
乘法 |
DIV
|
除法 |
AND
|
邏輯與 |
OR
|
邏輯或 |
NOT
|
邏輯取反 |
其中算術(shù)和邏輯指令是順序編程的基礎(chǔ)。通過(guò)邏輯比較影響狀態(tài)寄存器,再結(jié)合有條件跳轉(zhuǎn)指令就可以實(shí)現(xiàn)更復(fù)雜的分支或循環(huán)結(jié)構(gòu)。需要注意的是 MUL
和 DIV
等乘除法指令可能隱含使用了某些寄存器,指令細(xì)節(jié)請(qǐng)查閱相關(guān)手冊(cè)。
控制流指令有 CMP
、JMP-if-x
、JMP
、CALL
、RET
等指令。CMP
指令用于兩個(gè)操作數(shù)做減法,根據(jù)比較結(jié)果設(shè)置狀態(tài)寄存器的符號(hào)位和零位,可以用于有條件跳轉(zhuǎn)的跳轉(zhuǎn)條件。JMP-if-x
是一組有條件跳轉(zhuǎn)指令,常用的有 JL
、JLZ
、JE
、JNE
、JG
、JGE
等指令,對(duì)應(yīng)小于、小于等于、等于、不等于、大于和大于等于等條件時(shí)跳轉(zhuǎn)。JMP
指令則對(duì)應(yīng)無(wú)條件跳轉(zhuǎn),將要跳轉(zhuǎn)的地址設(shè)置到
IP 指令寄存器就實(shí)現(xiàn)了跳轉(zhuǎn)。而 CALL
和 RET
指令分別為調(diào)用函數(shù)和函數(shù)返回指令。
名稱 | 解釋 |
---|---|
JMP
|
無(wú)條件跳轉(zhuǎn) |
JMP-if-x
|
有條件跳轉(zhuǎn),JL 、JLZ 、JE 、JNE 、JG 、JGE
|
CALL
|
調(diào)用函數(shù) |
RET
|
函數(shù)返回 |
無(wú)條件和有條件調(diào)整指令是實(shí)現(xiàn)分支和循環(huán)控制流的基礎(chǔ)指令。理論上,我們也可以通過(guò)跳轉(zhuǎn)指令實(shí)現(xiàn)函數(shù)的調(diào)用和返回功能。不過(guò)因?yàn)槟壳昂瘮?shù)已經(jīng)是現(xiàn)代計(jì)算機(jī)中的一個(gè)最基礎(chǔ)的抽象,因此大部分的 CPU 都針對(duì)函數(shù)的調(diào)用和返回提供了專有的指令和寄存器。
其它比較重要的指令有 LEA
、PUSH
、POP
等幾個(gè)。其中 LEA 指令將標(biāo)準(zhǔn)參數(shù)格式中的內(nèi)存地址加載到寄存器(而不是加載內(nèi)存位置的內(nèi)容)。PUSH
和 POP
分別是壓棧和出棧指令,通用寄存器中的 SP
為棧指針,棧是向低地址方向增長(zhǎng)的。
名稱 | 解釋 |
---|---|
LEA
|
取地址 |
PUSH
|
壓棧 |
POP
|
出棧 |
當(dāng)需要通過(guò)間接索引的方式訪問(wèn)數(shù)組或結(jié)構(gòu)體等某些成員對(duì)應(yīng)的內(nèi)存時(shí),可以用 LEA 指令先對(duì)目前內(nèi)存取地址,然后在操作對(duì)應(yīng)內(nèi)存的數(shù)據(jù)。而棧指令則可以用于函數(shù)調(diào)整自己的棧空間大小。
最后需要說(shuō)明的是,Go 匯編語(yǔ)言可能并沒(méi)有支持全部的 CPU 指令。如果遇到?jīng)]有支持的 CPU 指令,可以通過(guò) Go 匯編語(yǔ)言提供的 BYTE 命令將真實(shí)的 CPU 指令對(duì)應(yīng)的機(jī)器碼填充到對(duì)應(yīng)的位置。完整的 X86 指令在 https://github.com/golang/arch/blob/master/x86/x86.csv 文件定義。同時(shí)
Go 匯編還正對(duì)一些指令定義了別名,具體可以參考這里 https://golang.org/src/cmd/internal/obj/x86/anames.go。
![]() |
![]() |
更多建議: