title: What are R10-R15 registers used for in the Windows x64 calling convention?
body: <p>From Intel's introduction to x64 assembly at <a href="https://software.intel.com/en-us/articles/introduction-to-x64-assembly" rel="nofollow noreferrer">https://software.intel.com/en-us/articles/introduction-to-x64-assembly</a>,</p>
  
  <ul>
  <li>RCX, RDX, R8, R9 are used for integer and pointer arguments in that order left to right.</li>
  <li>Registers RAX, RCX, RDX, R8, R9, R10, and R11 are considered volatile and must be considered destroyed on function calls.</li>
  <li>RBX, RBP, RDI, RSI, R12, R14, R14, and R15 must be saved in any function using them.</li>
  </ul>
  
  <p>While I understand how RCX, RDX, R8, R9 are used as function arguments, I've seen functions that take more than 4 arguments revert to using the stack like 32 bit code. An example is below:</p>
  
  <pre><code>sub_18000BF10   proc near 
  lpDirectory     = qword ptr -638h
  nShowCmd        = dword ptr -630h
  Parameters      = word ptr -628h
  
               sub     rsp, 658h
               mov     r9, rcx
               mov     r8, rdx
               lea     rdx, someCommand ; "echo "Hello""...
               lea     rcx, [rsp+658h+Parameters] ; LPWSTR
               call    cs:wsprintfW
               xor     r11d, r11d
               lea     r9, [rsp+658h+Parameters] ; lpParameters
               mov     [rsp+658h+nShowCmd], r11d ; nShowCmd
               lea     r8, aCmdExe     ; "cmd.exe"
               lea     rdx, Operation  ; "open"
               xor     ecx, ecx        ; hwnd
               mov     [rsp+658h+lpDirectory], r11 ; lpDirectory
               call    cs:ShellExecuteW
               mov     eax, 1
               add     rsp, 658h
               retn
  sub_18000BF10    endp
  </code></pre>
  
  <p>This is an excerpt from IDA, and you can see the nShowCmd and lpDirectory arguments to ShellExecute are on the stack. <strong>Why cant we use the extra registers after R9 for fast-call behavior?</strong></p>
  
  <p>Or if we can do that in user-defined functions and the system API functions don't do that, is there a reason for it? I imagine fast-call arguments in registers would be more efficient than checking, offsetting the stack.</p>