2026 05 26 12 34 [C] VC compiler的最佳化
剛剛猛看這段組語還以為編譯器弄錯了.
因為 dec rcx (idx) 被放在後面了.​
​   
​       int idx = CRYPTO_SIZE_QUIC_IV;
          while (full_pn != 0 && idx > 0) {
  00007FF7F2EBA6E3  test        rax,rax
  00007FF7F2EBA6E6  je          $err_to_free+3Ch (07FF7F2EBA708h)
  00007FF7F2EBA6E8  mov         ecx,0Ch
  00007FF7F2EBA6ED  nop         dword ptr [rax]
  00007FF7F2EBA6F0  test        rcx,rcx
  00007FF7F2EBA6F3  jle         $err_to_free+3Ch (07FF7F2EBA708h)
              hkdf_res.quic_iv[--idx] ^= full_pn & 0xff;
  00007FF7F2EBA6F5  xor         byte ptr [rsp+rcx+0AFh],al
  00007FF7F2EBA6FC  dec         rcx
              full_pn >>= 8;
  00007FF7F2EBA6FF  shr         rax,8
  00007FF7F2EBA703  test        rax,rax
  00007FF7F2EBA706  jne         $err_to_free+24h (07FF7F2EBA6F0h)
          }
      } 

​我為了再次確認, 問了 claude code, 它認為這是正確的.
以下是 claude code的回答.​
​ dec rcx 的位置是正確的。這是編譯器實作 --idx(前置遞減)的一種等價轉換。

  關鍵:offset 從 0xB0 調整為 0xAF

  假設 quic_iv 的起始位址是 [rsp + 0xB0],C 語言的 quic_iv[--idx] 語意是:

  先把 idx 減 1,再用新的 idx 當索引

  編譯器有兩種等價的組語寫法:

  寫法 A(dec 在前):
  dec rcx                          ; idx = 12 → 11
  xor byte ptr [rsp + rcx + 0B0h] ; quic_iv[11]

  寫法 B(dec 在後,offset 補償)← 編譯器選擇的版本:
  xor byte ptr [rsp + rcx + 0AFh] ; 0xAF = 0xB0 - 1,等同 quic_iv[rcx-1] = quic_iv[11]
  dec rcx                          ; idx: 12 → 11,留給下一輪迴圈條件使用

  寫法 A(dec 在前):
  dec rcx                          ; idx = 12 → 11
  xor byte ptr [rsp + rcx + 0B0h] ; quic_iv[11]
  xor byte ptr [rsp + rcx + 0B0h] ; quic_iv[11]

  寫法 B(dec 在後,offset 補償)← 編譯器選擇的版本:
  xor byte ptr [rsp + rcx + 0AFh] ; 0xAF = 0xB0 - 1,等同 quic_iv[rcx-1] = quic_iv[11]
  dec rcx                          ; idx: 12 → 11,留給下一輪迴圈條件使用

  兩種寫法在每次迭代存取的位址完全相同,因為 0xAF = 0xB0 - 1 把「還沒遞減」的差距直接補在常數 offset 上。

​我才知道現在編譯器最佳化有到這種程度了.
PS: 我有去驗證的確編譯器是有偷減offset.
​​