程式的機器級表示練習題 (Practice - Machine-Level Programs)


Question 1 - mov 指令限制 [recall]

同事寫了一行組語 movq (%rax), (%rbx),想把一個 quad word 從某記憶體位置直接複製到另一個記憶體位置,結果組譯失敗。
請說明原因,以及正確的做法。


Question 2 - 部分暫存器寫入慣例 [recall]

已知 %rax = 0x0011223344556677。分別執行以下三條指令(各自獨立,都從此初始值開始),%rax 最後的值是多少?

movb $-1, %al
movw $-1, %ax
movl $-1, %eax

Question 3 - 定址模式計算 [application]

已知 %rdx = 0xf000%rcx = 0x0100,記憶體 M[0xf400] = 0xAB
求下列各 operand 的值:(a) $0x100 (b) 0xf000 (c) (%rdx,%rcx) (d) 0x300(%rdx,%rcx,4)


Question 4 - leaq 的算術用途 [application]

函式參數 x%rdiy%rsi。編譯器產生:

leaq (%rdi,%rsi,4), %rax
leaq (%rax,%rax,2), %rax

執行完後 %rax 是 x 與 y 的什麼運算式?這兩條指令有讀取記憶體嗎?


Question 5 - Condition codes 與 cmp/test [recall]

說出 x86-64 四個 condition code 旗標的名稱與意義,並說明 cmpq %rsi, %rditestq %rax, %rax 各依據什麼運算設定旗標。


Question 6 - set 指令與完整結果 [recall]

組語中出現 setl %al。後綴 l 是表示 operand 大小為 4 bytes 嗎?若要把比較結果變成完整的 32-bit int 回傳值,後面還需要哪條指令?


Question 7 - PC-relative 跳轉計算 [application]

反組譯輸出如下(左為位址、中為機器碼):

  4004d0: 48 89 f8    mov  %rdi,%rax
  4004d3: eb 03       jmp  XXXXXX
  4004d5: 48 d1 f8    sar  %rax

jmp 指令的目標位址 XXXXXX 是多少?若 offset byte 是 0xf8 而非 0x03,目標又是多少?


Question 8 - call/ret 與返回位址 [recall]

main 中位址 0x400563 處有一條 5-byte 的指令 callq 400540 <multstore>,執行前 %rsp = 0x7fffffffe840
執行 callq 後:(a) %rsp 是多少?(b) M[%rsp] 存什麼值?(c) 這個返回位址屬於誰的 stack frame?


Question 9 - 參數傳遞慣例 [recall]

函式 void proc(long a, int b, char c, short d, long e, int f, long g, char *h) 共 8 個引數。
前 6 個引數各放在哪個暫存器(注意大小)?第 7、8 個引數放哪?被呼叫者透過什麼位址存取它們?


Question 10 - callee-saved 暫存器 [recall]

哪些暫存器是 x86-64 的 callee-saved?若函式 P 有一個值需要跨越對 Q 的呼叫仍然存活,有哪兩種做法?


Question 11 - 二維陣列位址反推 [analysis]

某函式 int f(long i, long j) 回傳 A[i][j],其中 Aint A[M][N]。gcc 產生:

leaq (%rdi,%rdi,2), %rax      # i 在 %rdi、j 在 %rsi
leaq (%rdi,%rax,4), %rax
addq %rsi, %rax
movl A(,%rax,4), %eax

由這段組語能否推出 N?N 是多少?請說明由組語反推二維陣列維度的一般方法(M 能否推出?)。


Question 12 - 指標 cast 與縮放 [application]

pchar *,其值為位址 p。以下兩個 C 運算式各計算出什麼位址?

(a) (int *) p + 7 (b) (int *) (p + 7)


Question 13 - buffer overflow 機制與防禦 [recall]

函式內有 char buf[8] 位於 %rsp(stack top),return address 在 %rsp+24,中間 16 bytes 未使用。程式用 gets 讀入字串。
(a) 輸入幾個字元會覆寫 return address?(b) 說出現代系統的三道防禦機制。


Question 14 - cmov 的適用限制 [analysis]

以下函式被學生手動「最佳化」成 conditional move 版本:

long cread(long *xp) {
    return (xp ? *xp : 0);
}
cread_cmov:
  movq (%rdi), %rax      # v = *xp
  testq %rdi, %rdi
  movl $0, %edx
  cmove %rdx, %rax       # if (xp==NULL) v = 0
  ret

這段 cmov 版本有什麼致命問題?並歸納哪兩類情況不能或不該用 conditional move。


Question 15 - 浮點呼叫慣例 [recall]

函式宣告為 double f(int x, double y, long z, float w)
(a) 四個參數各放在哪個暫存器?(b) 回傳值放哪?(c) 若 f 內部要讓一個浮點值跨越函式呼叫存活,能放某個 callee-saved 的 XMM 暫存器嗎?


Question 16 - 浮點轉換與運算指令 [recall]

(a) C 的 (long) d(d 為 double)對應哪條指令?其捨入方式為何?
(b) vsubsd %xmm2, %xmm0, %xmm0 計算的是什麼?
(c) vmovaps 用於讀寫記憶體時要注意什麼?