Y86-64指令集体系结构
目錄
前言:
1.程序員可見狀態
?2.Y86-64指令
3.指令編碼
movq指令
整數操作指令
跳轉指令
條件傳送指令
call和ret指令?
push和pop指令?
halt和nop指令
4.Y86-64異常
5.Y86-64程序
前言:
本章內容是筆者學習csapp的一些讀書筆記,其中大部分內容來自原書,并加入了一些自己的注釋
指令系統是計算機軟件和硬件交互的接口,由于x86指令集相對復雜,書中定義了一個簡單的指令集 “Y86-64” ,能夠滿足一個處理器對于指令集的基本需求
1.程序員可見狀態
在這里,“程序員” 既可以是用匯編代碼寫程序的人,也可以是產生機器級代碼的編譯器
程序員的可見狀態是指:Y86-64中的每條指令都會讀取或者修改處理器狀態的某些部分,如程序寄存器、條件碼、程序計數器(PC)、內存以及程序狀態等等
? 對于程序寄存器,相比于x86,%rsp也是被用作棧指針,而Y86-64指令集體系結構中少了程序寄存器%r15,這么做的目的降低編碼的復雜度,這一點會在后面提及
? 條件碼有3個,分別是ZF、SF、OF (有關條件碼的內容可以參考)條件碼、條件控制和條件傳送_七月不遠.的博客-CSDN博客https://blog.csdn.net/weixin_58165485/article/details/123466697?spm=1001.2014.3001.5502? 程序計數器(PC)存放當前正在執行指令的地址 (注意:是地址而并非內容)
? 程序狀態碼表明這條指令是否正常運行
?2.Y86-64指令
相比于x86-64指令集,Y86-64指令集做了相應的簡化:
??movq指令
?x86-64中的movq指令在這里被分為四種,分別是:
| Source operand | Destination operand | |
| irmovq | Immediate | Register |
| rrmovq | Register | Register |
| rmmovq | Register | Memory |
| mrmovq | Memory | Register |
指令的第一個字母表示源操作數的類型,第二個字母表示目的操作數的類型,源操作數可以是立即數(i)?,寄存器(r),內存(m),目的操作數可以是寄存器(r)和內存(m)
- irmovq指令表示將一個立即數存進一個寄存器中?
- rrmovq指令表示將一個寄存器中的值存進一個寄存器中
- rmmovq指令表示將一個寄存器中的值存進一個內存地址所對應的內存中
- mrmovq指令表示將一個內存中的值存進一個寄存器中
值得注意的是,我們不能:
- 從一個內存地址直接傳送到另一個內存地址,形如mmmovq是不被允許的
- 將立即數直接傳送到內存,形如immovq是不被允許的?
? 整數操作指令
Y86-64定義了4個整數操作指令,分別是加(addq),減(subq),與(andq),異或(xorq)?
- 只能對寄存器數據進行操作 (這點很重要,x86-64中還允許對內存進行操作)
- 會設置條件碼
? 跳轉指令?
跳轉指令形如 jXX,Y86-64定義了7個跳轉指令,分別是:
| 指令 | 跳轉條件 | 描述 |
| jmp | 1 | 直接跳轉 |
| jle | (SF ^ OF) | ZF | 小于或等于 (有符號 <=) |
| jl | SF ^ OF | 小于 (有符號 <) |
| je | ZF | 相等 / 零 |
| jne | ~ZF | 不相等 / 非零 |
| jge | ~(SF ^ OF) | 大于或等于(有符號 >=) |
| jg | ~(SF ^ OF) & ~ZF | 大于(有符號 >) |
根據分支指令的類型和條件代碼的設置來選擇分支?
? 條件傳送指令?
有6個條件傳送指令,形如comvXX:cmovle,cmovl,cmove,cmovne,cmovge,cmovg?
指令格式和rrmovq一樣,但只有滿足條件碼組合時才發生傳送?
? call指令和ret指令
- call指令的作用是將返回地址入棧,然后跳到目的地址
- ret指令從這樣的調用中返回
? push指令和pop指令
分別實現入棧和出棧,依靠%rsp來實現?
? halt指令?
halt指令會停止指令的執行,導致處理器停止,并將狀態碼設置為HLT?
3.指令編碼
對于每條指令,Y86-64規定需要1~10個字節不等的編碼長度,如ret指令只需要1個字節就能完成編碼,而irmovq需要10個字節來完成編碼
每條指令的第一個字節表明了指令的類型,它相當于我們的身份證,前六位指明了你所在的地址,而這個字節分為兩個部分,每個部分占4個比特位,高4位表示指令代碼 (icode),第4位表示指令功能 (ifun),下面會有詳細介紹
當指令中有寄存器類型的操作數時,會在后面附加一個字節稱為寄存器指示符字節,用來顯示地給出將要操作地寄存器ID
Y86-64對于15個程序寄存器都給了一個ID,稱為寄存器標識符(register ID)?
| 數字 | 寄存器名稱 | 數字 | 寄存器名稱 | |
| 0 | %rax | 8 | %r8 | |
| 1 | %rcx | 9 | %r9 | |
| 2 | %rdx | A | %r10 | |
| 3 | %rbx | B | %r11 | |
| 4 | %rsp | C | %r12 | |
| 5 | %rbp | D | %r13 | |
| 6 | %rsi | E | %r14 | |
| 7 | %rdi | F | 無寄存器 |
相比于x86-64省略掉寄存器%r15,是為了滿足編碼地簡便性,我們可以用4個比特位來描述所有寄存器類型,從0000~1111剛好16個數,而不需要再多用一個比特位來保存17種情況
下面介紹每種指令的編碼形式:?
movq指令
🔰
以rrmovq為例,rrmovq指令是將一個寄存器的值傳送到另一個寄存器中,其編碼有兩個字節長度
第一個字節是 2 0 ,2表示指令代碼,0表示指令功能,當處理器拿到的指令形式為2 0 rA rB時,首先讀到 2 0,處理器知道了這是兩個寄存器之間傳送指令,寄存器指示符字節給出了 rA,rB,指明了即將用到地兩個寄存器ID,因此處理器就會根據這條編碼,將 rA 的值傳送到 rB 中
?🔰
對于irmovq,它表示將一個立即數傳送到寄存器中,其編碼長度有10個字節?
3 0代表的是irmovq,處理器讀到3 0便知道要將一個立即數傳到寄存器,但是在這個過程中只有1個寄存器作為目的操作數被用到,因此在寄存器指示符字節源操作數中是F,表明不需要寄存器,而在后面的8字節中保存的就是這個立即數V,處理器將V傳送到寄存器 rB 中
🔰
rmmovq和mrmovq中的8字節常數字是一個地址偏移量,表明將內存引用的地址是rB內的地址+偏移量D?
整數操作指令
之前已經說過,整數操作指令只能對兩個寄存器中的數據進行操作,因此,只需要2個字節就能完成編碼
- 第一個字節 6 fn?,前4位 (6) 指出這是一個整數操作符,后4位(fn)則是指令功能位
? ? ? fn = 0 1 2 3分別對應四種規定的整數運算?
- 第二個字節是寄存器指示符字節,指明了即將操作的兩個寄存器ID
因此,類似 6 1 2 3這種編碼意思就是將寄存器 %rdx 中的值減去寄存器 %rbx 中的值,并把返回結果保存到?%rdx中
跳轉指令
和整數操作指令類似,跳轉指令也有功能之分,ifun部分分為0~7:
?后面的Dest指明了要跳轉的地址,如果滿足條件,則下一條指令跳轉到這個絕對地址執行
注意:分支指令和調用指令的目的一定是一個絕對地址,而不像IA32中那樣使用PC相對尋址?
條件傳送指令
和跳轉指令類似,條件傳送指令的fn分為0~6:
當fn = 0時,代表無條件傳送,也就是我們之前提到的rrmovq
其余的fn都是需要條件碼滿足條件時,才更新目的寄存器的值?
call和ret指令?
call和ret指令分別實現函數調用和返回,其中
- call指令需要9個字節來編碼,除了第一個字節外,剩下部分是一個絕對地址指向調用函數的地址?
- ret指令返回的地址存儲在棧上,故不需要在指令中給出
push和pop指令?
push和pop指令分別實現入棧和出棧的操作,注意的是即使編碼中只有rA一個目的操作數,但實際上這兩條指令也同時調用了%rsp(棧指針)?
halt和nop指令
- halt:停止指令的執行
- nop:執行一個空操作?
練習:rmmovq %rsp,0x123456789abcd(%rdx)?進行編碼?
rmmovq的第一個字節是40,%rsp的編號是4,%rdx編號是2,因此前兩個字節編碼是4042,而rmmovq的編碼規則將地址偏移量放在后8字節的常數字中,故在小端機器上的編碼為:
4042cdab896745230100?
4.Y86-64異常
對于Y86-64來說,程序員可見狀態包括了狀態碼Stat,其可能的值如下:
| 值 | 名稱 | 含義 |
| 1 | AOK | 正常操作 |
| 2 | HLT | 遇到器執行halt指令 |
| 3 | ADR | 遇到非法地址 |
| 4 | INS | 遇到非法指令 |
5.Y86-64程序
對于下面代碼,用sum函數計算一個整數數組的和:
long sum(long* start, long count) {long sum = 0;while (count) {sum += *start;start++;count--;}return sum; }x86-64(由GCC產生)和Y86-64匯編代碼如下:?
我們可以很清楚地看到一些差別:
- Y86-64在第2~3行將兩個數加載到兩個寄存器中,因為不允許在整數操作中使用立即數,只能使用寄存器
- Y86-64在第8~9行先將一個數從內存中取到寄存器中,再完成加法,因為不允許在內存的數與寄存器的數相加
總結
以上是生活随笔為你收集整理的Y86-64指令集体系结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对电影题材分析的案例-电影类型与电影利润
- 下一篇: 蓝牙及蓝牙通讯Bluetooth概述