c assembly linux-kernel system-calls calling-convention

¿Se requiere "asmlinkage" para llamar a la función ac desde el ensamblaje?



assembly linux-kernel (3)

La idea, creo, es permitir que el kernel se compile con las opciones de gcc que cambiarían la convención de llamadas predeterminada a algo más eficiente (es decir, pasar más argumentos en los registros). Sin embargo, no se puede permitir que las funciones que necesitan ser llamadas desde asm varíen en la convención de llamadas en función de las opciones de gcc en uso, o debería haber versiones separadas del asm para cada conjunto compatible de opciones de gcc. Por lo tanto, las funciones que necesitan utilizar una convención de llamada fija (que coincide con el valor predeterminado sin opciones especiales de gcc) se declaran con atributos especiales para que su convención de llamadas permanezca fija.

Estoy escribiendo una función C que se invocará desde el código ensamblador.

(Específicamente, quiero hacer algún trabajo de comprobación en el camino de manejo de llamadas del sistema en el kernel de Linux, así que llamaré a la función c antes de que se envíe una llamada al sistema en entry_32.S)

Estoy confundido con el modificador "asmlinkage" cuando defino mi función c.

Sé que como enlace es decirle al compilador que los parámetros se pasarán a través de la pila.

#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))

Preguntas:

(1) ¿Se requiere un enlace intermedio al definir una función que se invocará desde el código de ensamblado?

(2) cuál es la convención de llamada predeterminada en gcc. Si omito "asmlinkage" cuando defino la función ac, ¿implica _cdecl o fastcall?

(3) si la convención de llamadas predeterminada es cdecl, ¿por qué es necesario un enlace indirecto, considerando que cdecl es igual al modificador de enlaces intermedios? (¿Estoy correcto aquí?)

(4) ¿por qué esas funciones de llamada del sistema están declaradas con asmlinkage? ¿Podemos copiar los parámetros a los registros primero, luego llamar a esas funciones de llamadas del sistema? Desde mi punto de vista, en x86, al emitir una llamada al sistema, los parámetros se guardan fácilmente en registros; entonces, ¿por qué molestarse en guardarlos luego en stack para hacer cumplir esos parámetros de aprobación a través de la convención de pila?

Finalmente, ¿alguien puede recomendar algunos recursos / libros a los que pueda referirme para dicha combinación de ensamblaje / programación c?


Después de varias horas de investigación, obtuve los siguientes puntos empíricos:

(1) ¿Se requiere un enlace intermedio para definir una función que se invocará desde el código de ensamblado?

No. En realidad, la llamada rápida se usa con frecuencia.

Por ejemplo, en entry_32.S, si busca "call", puede obtener todas las funciones c invocadas desde este archivo de ensamblaje. Entonces puede ver que muchos usan llamadas rápidas en lugar de enlaces intermedios como la convención de llamadas. Por ejemplo,

/*in entry_32.S*/ movl PT_OLDESP(%esp), %eax movl %esp, %edx call patch_espfix_desc /*in traps_32.c*/ fastcall unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)

(2) cuál es la convención de llamada predeterminada en gcc. Si omito "asmlinkage" cuando defino la función ac, ¿implica _cdecl o fastcall?

(3) si la convención de llamadas predeterminada es cdecl, ¿por qué es necesario un enlace indirecto, considerando que cdecl es igual al modificador de enlaces intermedios? (¿Estoy correcto aquí?)

Para las funciones C que no se invocan desde el código ensamblador, podemos suponer con seguridad que la convención de llamada predeterminada es cdecl (o llamada rápida; no importa, porque gcc se ocupará de la persona que llama y llamará para pasar los parámetros. La convención de llamada predeterminada puede ser especificado al compilar). Sin embargo, para las funciones C invocadas desde el código ensamblador, deberíamos declarar explícitamente la convención de llamada de la función, porque el código de paso del parámetro en el lado del ensamblaje ha sido corregido. Por ejemplo, si patch_espfix_desc se declara como asmlinkage, entonces gcc compilará la función para recuperar los parámetros de la pila. Esto es inconsistente con el lado del montaje, que pone los parámetros en los registros.

Pero todavía no tengo claro cuándo utilizar el enlace indirecto y cuándo usar la llamada rápida. Realmente necesito algunas pautas y recursos para referirme.


Me gustaría intentar responder la pregunta (4) yo mismo:

¿Por qué todas las funciones de llamada al sistema sys_ *, p. Ej. Sys_gettimeofday, usan pila para pasar parámetros?

La razón es que, de todos modos, el kernel necesita guardar todos los registros en la pila (para restaurar el entorno antes de volver al espacio de usuario) cuando maneja las solicitudes de llamadas del sistema desde el espacio de usuario, por lo que los parámetros están disponibles en la pila. Es decir, no necesita un esfuerzo extra.

Por otro lado, si desea utilizar la llamada rápida para la convención de llamadas, debe trabajar más. Primero necesitamos saber, cuando un programa de usuario emite una llamada al sistema, en x86-linux,% eax es para el número de syscall, y % ebx,% ecx,% edx,% esi,% edi,% ebp se usan para pasar 6 parámetros a las llamadas al sistema (antes de "int 80h" o "sysenter"). Sin embargo, la convención de llamada de fastcall es pasar el primer parámetro en% eax, el 2º en% edx, el 3%% ecx, otros se empujan a la pila de derecha a izquierda. De esta forma, para hacer cumplir esta convención de llamadas rápidas en Kernel, necesita organizarlas de alguna manera además de guardar todos los registros en la pila.