Est-ce que “asmlinkage” est nécessaire pour que la fonction ac soit appelée depuis l’assembly?

J’écris une fonction C qui sera appelée à partir du code de l’assembly.

(Plus précisément, je souhaite effectuer certaines tâches de vérification dans le chemin de la gestion des appels système dans le kernel Linux, donc je vais appeler la fonction c avant qu’un appel système ne soit dissortingbué dans entry_32.S)

Je suis confondu avec le modificateur “asmlinkage” lors de la définition de ma fonction c.

Je sais qu’asmlinkage consiste à indiquer au compilateur que les parameters seront transmis via stack.

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

Des questions:

(1) Est-ce que asmlinkage est nécessaire pour définir une telle fonction qui sera appelée à partir du code assembleur?

(2) quelle est la convention d’appel par défaut dans gcc. Si j’omets “asmlinkage” lors de la définition de la fonction ac, cela implique-t-il _cdecl ou fastcall?

(3) Si la convention d’appel par défaut est cdecl, pourquoi asmlinkage est-il nécessaire, considérant que cdecl est égal à modificateur asmlinkage? (est-ce que j’ai raison ici?)

(4) Pourquoi ces fonctions d’appel système sont-elles toutes déclarées avec asmlinkage? Pouvons-nous d’abord copier les parameters dans les registres, puis appeler ces fonctions d’appel système? De mon sharepoint vue, en x86, lors de l’émission d’un appel système, les parameters sont facilement sauvegardés dans des registres; alors pourquoi se donner la peine d’enregistrer ensuite dans la stack pour appliquer de tels parameters de passage via la convention de stack?

Enfin, quelqu’un peut-il recommander des ressources / livres auxquels je peux me référer pour un tel mélange assemblage / programmation c?

Après plusieurs heures de recherche, j’ai obtenu les points empiriques suivants:

(1) Est-ce que asmlinkage est nécessaire pour définir une telle fonction qui sera appelée à partir du code assembleur?

En fait, le fastcall est fréquemment utilisé.

Par exemple, dans entry_32.S, si vous recherchez “call”, vous pouvez obtenir toutes les fonctions c invoquées à partir de ce fichier d’assemblage. Ensuite, vous pouvez voir que beaucoup utilisent fastcall au lieu d’asmlinkage comme convention d’appel. Par exemple,

  /*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) quelle est la convention d’appel par défaut dans gcc. Si j’omets “asmlinkage” lors de la définition de la fonction ac, cela implique-t-il _cdecl ou fastcall?

(3) Si la convention d’appel par défaut est cdecl, pourquoi asmlinkage est-il nécessaire, considérant que cdecl est égal à modificateur asmlinkage? (est-ce que j’ai raison ici?)

Pour les fonctions C non appelées à partir du code de l’assembly, nous pouvons sans risque supposer que la convention d’appel par défaut est cdecl (ou appel rapide; peu importe, car gcc se chargera de l’appelant et sera appelé pour le passage des parameters. La convention d’appel par défaut peut être spécifié lors de la compilation). Cependant, pour les fonctions C appelées à partir du code d’assembly, nous devrions explicitement déclarer la convention d’appel de la fonction, car le paramètre qui passe le code du côté assembleur a été corrigé. Par exemple, si patch_espfix_desc est déclaré comme asmlinkage, alors gcc comstackra la fonction pour extraire les parameters de la stack. Ceci est incompatible avec le côté assemblage, qui place les parameters dans des registres.

Mais je ne sais toujours pas quand utiliser asmlinkage et quand utiliser fastcall. J’ai vraiment besoin de directives et de ressources.

J’aimerais essayer de répondre moi-même à la question (4):

Pourquoi toutes les fonctions d’appel système sys_ *, par exemple sys_gettimeofday, utilisent-elles stack pour passer des parameters?

La raison en est que de toute façon le kernel a besoin de sauvegarder tous les registres sur la stack (afin de restaurer l’environnement avant de revenir à l’espace utilisateur) lors du traitement des demandes d’appel système depuis l’espace utilisateur, donc après que les parameters soient disponibles sur la stack. C’est-à-dire que cela ne nécessite pas d’effort supplémentaire.

Par contre, si vous voulez utiliser fastcall pour la convention d’appel, il rest encore beaucoup à faire. Nous devons d’abord savoir, lorsqu’un programme utilisateur émet un appel système, dans x86-linux,% eax correspond au numéro syscall, et % ebx,% ecx,% edx,% esi,% edi,% ebp sont utilisés pour la transmission. 6 parameters aux appels système (avant “int 80h” ou “sysenter”). Cependant, la convention d’appel de fastcall est de passer le premier paramètre dans% eax, le deuxième dans% edx, le troisième% ecx, les autres sont poussés sur la stack de droite à gauche. De cette façon, pour appliquer cette convention fastcall dans le kernel, vous devez les organiser d’une manière ou d’une autre en plus de sauvegarder tous les registres de la stack.

Je pense que l’idée est de permettre au kernel d’être compilé avec des options gcc qui changeraient la convention d’appel par défaut en un moyen plus efficace (c’est-à-dire en transmettant plus d’arguments dans les registres). Toutefois, les conventions appelant ne doivent pas obligatoirement appeler les fonctions asm depuis asm, car il faudrait des versions distinctes de l’asm pour chaque ensemble d’options gcc pris en charge. Ainsi, les fonctions qui doivent utiliser une convention d’appel fixe (qui correspond à la valeur par défaut sans aucune option gcc spéciale) sont déclarées avec des atsortingbuts spéciaux afin que leur convention d’appel rest fixe.