En el ABI x86_64, si una función tiene argumentos variables, entonces se espera que AL
(que es parte de EAX
) contenga el número de registros vectoriales utilizados para contener argumentos para esa función.
En su ejemplo:
printf("%d", 1);
tiene un argumento entero así que no hay necesidad de un registro vectorial, por lo tanto, AL
se establece en 0.
Por otro lado, si cambia de ejemplo para:
printf("%f", 1.0f);
entonces el literal de coma flotante se almacena en un registro de vectores y, en consecuencia, AL
se establece en 1
:
movsd LC1(%rip), %xmm0
leaq LC0(%rip), %rdi
movl $1, %eax
call _printf
Como era de esperar:
printf("%f %f", 1.0f, 2.0f);
hará que el compilador para configurar AL
-2
ya que hay dos argumentos de coma flotante:
movsd LC0(%rip), %xmm0
movapd %xmm0, %xmm1
movsd LC2(%rip), %xmm0
leaq LC1(%rip), %rdi
movl $2, %eax
call _printf
En cuanto a sus otras preguntas:
puts
también está poniendo a cero %eax
justo antes de la llamada pesar de que sólo toma un solo puntero. ¿Por qué es esto?
No debería. Por ejemplo:
#include <stdio.h>
void test(void) {
puts("foo");
}
cuando se compila con gcc -c -O0 -S
, salidas:
pushq %rbp
movq %rsp, %rbp
leaq LC0(%rip), %rdi
call _puts
leave
ret
y %eax
no se pone a cero. Sin embargo, si se quita #include <stdio.h>
continuación, el conjunto resultante hace cero a cabo %eax
justo antes de llamar puts()
:
pushq %rbp
movq %rsp, %rbp
leaq LC0(%rip), %rdi
movl $0, %eax
call _puts
leave
ret
La razón está relacionada con su segunda pregunta:
Esto también ocurre antes de cualquier llamada a mi propia void proc() función (incluso con -O2 establecido), pero no se pone a cero cuando se llama a una función void proc2 (int param).
Si el compilador no ve la declaración de una función, no hace suposiciones sobre sus parámetros, y la función podría aceptar argumentos variables. Lo mismo se aplica si especifica una lista de parámetros vacía (que no debería, y está marcada como una característica obsoleta C por ISO/IEC). Dado que el compilador no tiene suficiente información sobre los parámetros de la función, se pone a cero %eax
antes de llamar a la función porque podría ser el caso de que la función se define como que tiene argumentos variables.
Por ejemplo:
#include <stdio.h>
void function() {
puts("foo");
}
void test(void) {
function();
}
donde function()
tiene una lista de parámetros vacía, da como resultado:
pushq %rbp
movq %rsp, %rbp
movl $0, %eax
call _function
leave
ret
Sin embargo, si se sigue la práctica de especificar void
recomiendan cuando la función no acepta parámetros, por ejemplo:
#include <stdio.h>
void function(void) {
puts("foo");
}
void test(void) {
function();
}
la n el compilador sabe que function()
no acepta argumentos - en particular, que no acepta argumentos variables - y por lo tanto no se borra %eax
antes de llamar a esa función:
pushq %rbp
movq %rsp, %rbp
call _function
leave
ret
'puts' está también poniendo a cero'% eax' justo antes de la llamada aunque solo toma un solo puntero. ¿Por qué es esto? – sh54
Esto también ocurre antes de cualquier llamada a mi propia función 'void proc()' (incluso con -O2 establecido), pero no se pone a cero cuando se llama a una función 'void proc2 (int param)'. – sh54
Para el registro, sucede antes de las llamadas a 'void proc()' porque esa firma en C en realidad no dice nada sobre el valor de proc, y podría ser una función variada, por lo que es necesario poner a cero el rax. 'void proc()' es diferente de 'void proc (void)'. Consulte http://stackoverflow.com/questions/693788/c-void-arguments – frangio