CSAPP(四)——處理器體系架構
阿新 • • 發佈:2022-05-12
指令集在CPU和程式設計師(編譯器)之間提供了一個抽象層,看起來,CPU在一條接著一條的順序執行編譯後的指令,但出於效能考慮實際情況卻遠比這個“看起來”要複雜。現代CPU使用一種稱作“流水線”的技術來執行每一條指令。
本章基於一種具有簡單指令集“Y86-64”的CPU架構進行研究,旨在對處理器的整個體系架構的瞭解更進一步。
Y86-64指令集體系結構
程式設計師可見的狀態
Y86-64指令
和x86-64不同的幾點:
- mov類命令,它的運算元型別必須由特定的字首指定,比如
rrmoveq
代表該mov指令的第一個運算元是一個暫存器,第二個也是一個暫存器。這使得我們對指令進行二進位制編碼時更加方便。mov類指令不允許mm
im/mi
操作,即記憶體到記憶體,記憶體和暫存器的直接移動。 - OPq類命令,即計算類命令,只有
addq
、subq
、andq
和xorq
,它們只對暫存器數進行操作,x86-64則允許對記憶體資料進行操作。這四個指令會設定條件碼 - halt指令導致處理器停止,並將狀態碼設定成HLT
指令由一個位元組進行編碼,高四位代表指令型別,低四位代表指令型別下細緻的操作型別,比如jXX
這種跳轉指令,它有jmp
、jle
、jne
等等。一些需要指定暫存器的指令需要一個位元組來指定使用哪個暫存器。同樣,高四位代表暫存器rA
(第一個運算元),低四位代表暫存器rB
(第二個運算元)。有些指令只需要一個暫存器,比如irmovq
rB
可以傳入,rA
固定為F
。dest
代表64位的目的地址,因為有的命令需要讀取記憶體地址。
如上是一些同類操作指令的細緻分類。
如上是Y86-64中包含的暫存器識別符號,它們被編碼為0~E,F表示沒有暫存器運算元。
練習題4.1
A:
irmovq $15, %rbx
30f3f000000000000000
B:
rrmovq %rbx, %rcx
2031
C:
rmmovq %rcx, -3(%rbx)
4013fdffffffffffffff
D:
addq %rbx, %rcx
6031
E:
jmp loop
700c01000000000000
練習題4.2
A: irmovq $-4, %rbx rmmovq %rsi, $0x800(%rbx) B: pushq %rsi call 0x20C #假設過程叫proc proc: irmoveq $10, rbx ret C: mrmovq 0x7(%rbp), %rsp nop f0 # 非法的一個指令 popq %rcx D: loop: subq %rcx, %rbx je loop # je 0x400 nop E: xorq %rsi, %rds pushq f0 # 這裡錯了, pushq 要求一個暫存器和,所以應該是[0~e]f
Y86-64異常
對於Y86-64,當遇到錯誤時直接停止執行指令,在更完善的設計中,處理器會呼叫一個異常處理程式來處理某種型別的異常。
Y86-64程式
上圖給出了同樣一段程式使用x86-64和Y86-64的對比。
- 由於Y86-64的運算指令只允許操作暫存器,不能操作立即數,所以,先使用
irmovq
將用於更新long指標和long資料的立即數$8
和$1
儲存到暫存器%r8
和%r9
中。同樣。第8~9行中由於運算指令只能操作暫存器,所以先將記憶體資料移到了暫存器中。 - 由於沒有
testq
指令,這裡使用了andq
指令。Y86-64中andq
也會設定條件碼,同樣的subq
也會,所有運算操作都會。所以我們無需在test
塊中引入判斷命令。
下圖是完整的程式檔案,包含初始化,程式結束等操作。
習題4.4
如下是x86-64版本,閱讀該程式碼。
rsum:
testq %rsi, %rsi
jle .L3
pushq %rbx
movq (%rdi), %rbx
subq $1, %rsi
addq $8, %rdi
call rsum
addq %rbx, %rax
popq %rbx
ret
.L3:
movl $0, %eax
ret
我們可以斷定%rsi儲存的是count,如果count為0了,就跳到.L3,返回0。
然後,就是常規操作,儲存%rbx到棧幀
%rdi我們可以斷定是start,那麼(%rdi)就是*start,=
把start中起始元素存到%rbx
然後增加start,減少count
再次呼叫rsum
然後將結果與%rbx中之前的資料相加,放到返回值中
彈出棧資料,返回
翻譯成Y86-64
rsum:
xor %rax, %rax
andq %rsi, %rsi
jle .L3
pushq %rbx
mrmovq (%rdi), %rbx
irmovq $8, %r8
irmovq $1, %r9
subq %r9, %rsi
addq %r8, %rdi
call rsum
addq %rbx, %rax
popq %rbx
ret
.L3:
ret
習題4.4/4.5
對我來說有點難啊
原始程式碼
sum:
irmovq $8, %r8
irmovq $1, %r9
xorq %rax, %rax
andq %rsi, %rsi
jmp test
loop:
mrmovq (%rdi), %r10 # 這裡%r10就是當前要加的陣列元素
addq %r10, %rax
addq %r8, %rdi
subq %r9, %rsi
test:
jne loop
ret
4.4 使用條件跳轉實現absSum
absSum:
irmovq $8, %r8
irmovq $1, %r9
xorq %rax, %rax
andq %rsi, %rsi
jmp test
loop:
mrmovq (%rdi), %r10
xorq %r11, %r11 # 將暫存器%r11置0
subq %r10, %r11 # 將%r10減去%r11放到%r11中
jle add # 如果是正數,也就是-x<=0 x>0,就直接相加
rrmovq %r11, %r10 # 如果是負數,將它的相反數儲存到%r10
add:
addq %r10, %rax
addq %r8, %rdi
subq %r9, %rsi
test:
jne loop
ret
4.5 使用條件控制實現absSum
absSum:
irmovq $8, %r8
irmovq $1, %r9
xorq %rax, %rax
andq %rsi, %rsi
jmp test
loop:
mrmovq (%rdi), %r10
xorq %r11, %r11 # 將暫存器%r11置0
subq %r10, %r11 # 將%r10減去%r11放到%r11中
cmovg %r11, %r10 # 如果 -x > 0,x = -x
addq %r10, %rax
addq %r8, %rdi
subq %r9, %rsi
test:
jne loop
ret
不管是哪種方式,思路就是
subq
取相反數,然後適當時候替換%r10。
未完...