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