I'm implementing a function using cpuid
in assembly according to AMD64 SysV ABI. I need 2 temporary registers to be used in the function itself: the first one to accumulate return value and the second one as a counter.
My function currently looks as:
;zero argument function
some_cpuid_fun:
push rbx
xor r10d, r10d ;counter initial value
xor r11d, r11d ;return value accumulator initial value
some_cpuid_fun_loop:
;...
cpuid
;update r10d and r11d according to the result
mov eax, r11d
pop rbx
ret
Since cpuid
clobbers eax
, ebx
, ecx
, edx
I cannot use them across different cpuid
executions. As documented in the AMD64 SysV ABI
:
r10 temporary register, used for passing a function’s
static chain pointer
r11 temporary register
There is only one strictly temporary register r11
, r10
seems to have a different purpose (and its usage as a loop counter is not one, I obviously did not pass any static chain pointers).
QUESTION: Is the some_cpuid_fun
function implementation AMD64 SysV ABI
compatible? If no how to rewrite it to stay compatible with the ABI?
After you have identified all the registers used for the arguments, none in this case, all you have to care about is if a register is volatile (not preserved across calls) or not.
In short, looks at the last column of the Figure 3.4 (where the usage for r10
come from): It is not preserved, so you can use it without restoring it.
The Usage column only tells you where to look for the arguments if expected and where to put the return value.
If you don't take a static chain pointer in input, you can overwrite r10
as soon as needed.
So yes, using r10
as a temporary register is ABI compatible.
For reference:
This subsection discusses usage of each register. Registers %rbp, %rbx and %r12 through %r15 “belong” to the calling function and the called function is required to preserve their values. In other words, a called function must preserve these registers’ values for its caller. Remaining registers “belong” to the called function. 5 If a calling function wants to preserve such a register value across a function call, it must save the value in its local stack frame.