這個題考察的是2.3.4和2.3.5節的一個定理:w比特長度的兩個數相乘,會産生一個2w長度的數,不管這兩個數是無符号數還是補碼表示的有符号數,把結果截取的低w比特都是相同的。
是以我們可以用無符号數乘法指令mulq實作有符号數乘法:先把數有符号擴充緻2w位,然後把這兩個2w位的數相乘,截取低2w位即可。
截取就是求模運算,即 mod 2^w。
A. x : %rdi n : %esi result : %rax mask : %rdx
B. result = 0 mask = 1
C. mask != 0
D. mask >>= n
E. result |= (x & mask)
這個地方也是很無語,在我的環境下必須将tmp的存儲類型設定為靜态存儲,并且将gcc的優化設定為O3,這樣才能生成使用conditional transfer的指令(才能讓gcc相信優化是值得的。。):
A. &A[i][j][k] = Xa + L(i*S*T + j*T + k)
B. R = 7,S = 5,T = 13
A. rdx (每次移位8,即按行移動)
B. rax(每次移位120 = 8 * 15,按列移動)
C. 由B,M = 15
NR(n)是數組的行數,是以我們找循環的次數,即rdi,得到rdi = 3n.
NC(n)是數組的列數,是以我們應該找每次循環更新時對指針增加的值,這個值等于sizeof(long) * NC(n),即r8,得到r8 = 8 * (4n + 1).
綜上,可知兩個宏定義:
A.

B. %rsp + 64
C. 通過以%rsp作為基位址,偏移8、16、24來擷取strA s的内容(由于中間夾了一個傳回位址,是以都要加8)
D. 通過傳進來的參數%rdi(%rsp + 64 + 8),以此作為基位址,偏移8、16、24來寫入strB r
E.
F. 我記得我在看《C語言程式設計: 現代方法 2rd》的時候,裡面說傳遞聚合類型的變量可以使用指針,這樣比傳遞整個資料結構要快一些(當然寫操作會改變實參)。這個題目裡面也都是讀操作,可以發現編譯器自動進行了優化——傳遞了基位址而非複制了整個資料結構。傳回就是在調用它的函數的棧幀中存入一個相關的資料結構。(這個題裡面process其實沒有棧幀,如果傳回位址算eval的話)
這題考察的是記憶體對齊。通過結構體成員的位置逐漸縮小範圍:
int t 為8(%rsi),是以4<B<=8
long u 為32(%rsi),是以24 < 8 + 4 + 2*a <= 32,得到6<A<=10
long y 為184(%rdi),是以176 < 4*A*B <= 184,得44 < A*B <=46。
是以AB = 45 或者AB = 46,結合A, B各自的範圍,隻可能為A = 9, B = 5.
A. 根據第4、5行的指令, idx的值為(bp + 40i + 8),由第1、2行指令,這裡的8是因為第一個int first整數和記憶體對齊的原因,是以每一個a_struct的大小為40位元組。
由于0x120 - 0x8 = 280位元組,是以CNT = 280/40 = 7.
B. 由第6、7行指令知,idx和x數組内元素都是signed long類型的。由于整個a_struct資料類型大小為40位元組,是以其内部應該為8*5 = 8 + 8*4:
e1.p : 0
e1.y : 8
e2.x : 0
e2.next : 8
B. 16 bytes
C.
A. andq $-16, X這條指令相當于将低4位置零,也就是使得rax中儲存的8n+30對16取整。是以s2-s1為8n+30對16取整的結果。
B. p的值為rsp(r8)-15對16取整的結果,確定了p數組的起始位址為16的整數倍。
C. 8n + 30對16取整有兩種可能:一種是8n本身就是16的整數倍即n = 2k,此時取整後為8n+16; 另一種是8n = 16k + 8即n = 2k + 1,此時取整後為8n + 24。由System V AMD64 ABI标準可知,s1的位址為16的整數倍(即結尾為0000),是以s2的位址也肯定是16的整數倍(結尾為0000)。又因p是由s2減15對16取整得到的結果,是以p和s2之間肯定相差2位元組,即e2 = 2 bytes. 是以e1最大為(n為奇數) :8n + 24 - 16 - 8n = 8 bit, 最小為(n為偶數):8n + 16 -16 - 8n = 0.(這個題我估計沒有考慮到ABI标準對于棧幀對齊的問題,s1的位址本來就應該是16的整數倍)
D. 由A B C可知,這種方法保證了s2 和 p的起始位址為16的整數倍,而且保證了e1最小為8n,能夠存儲p數組。
浮點數部分并未測試
A. 每一個複數變量使用兩個%xmm寄存器傳送。
B. 通過%xmm0和%xmm1傳回一個複數類型值。