Pour en savoir plus sur l'un des sujets, cliquez ici :The Definitive Guide to Linux System Calls
Je les ai vérifiés à l'aide de GNU Assembler (gas) sous Linux.
Interface noyau
Convention d'appel système Linux x86-32 alias i386 :
Dans x86-32, les paramètres d'appel système Linux sont transmis à l'aide de registres. %eax
pour syscall_number. %ebx, %ecx, %edx, %esi, %edi, %ebp sont utilisés pour passer 6 paramètres aux appels système.
La valeur de retour est en %eax
. Tous les autres registres (y compris EFLAGS) sont conservés sur int $0x80
.
J'ai pris l'extrait suivant du didacticiel d'assemblage Linux, mais j'ai des doutes à ce sujet. Si quelqu'un peut montrer un exemple, ce serait formidable.
S'il y a plus de six arguments,
%ebx
doit contenir l'emplacement de la mémoire où la liste des arguments est stockée - mais ne vous en faites pas car il est peu probable que vous utilisiez un appel système avec plus de six arguments.
Pour un exemple et un peu plus de lecture, reportez-vous à http://www.int80h.org/bsdasm/#alternate-calling-convention. Un autre exemple de Hello World pour i386 Linux utilisant int 0x80
:Bonjour, monde en langage assembleur avec appels système Linux ?
Il existe un moyen plus rapide d'effectuer des appels système 32 bits :en utilisant sysenter
. Le noyau mappe une page de mémoire dans chaque processus (le vDSO), avec le côté espace utilisateur du sysenter
dance, qui doit coopérer avec le noyau pour qu'il puisse trouver l'adresse de retour. Arg pour enregistrer le mappage est le même que pour int $0x80
. Vous devriez normalement appeler le vDSO au lieu d'utiliser sysenter
directement. (Voir Le guide définitif des appels système Linux pour plus d'informations sur la liaison et l'appel dans le vDSO, et pour plus d'informations sur sysenter
, et tout ce qui concerne les appels système.)
x86-32 [Free|Open|Net|DragonFly]Convention d'appel système UNIX BSD :
Les paramètres sont passés sur la pile. Poussez les paramètres (dernier paramètre poussé en premier) sur la pile. Poussez ensuite 32 bits supplémentaires de données factices (ce ne sont pas réellement des données factices. Reportez-vous au lien suivant pour plus d'informations), puis donnez une instruction d'appel système int $0x80
http://www.int80h.org/bsdasm/#default-calling-convention
Convention d'appel système Linux x86-64 :
(Remarque :x86-64 Mac OS X est similaire mais différent de Linux. À FAIRE :vérifiez ce que fait *BSD)
Reportez-vous à la section :"A.2 AMD64 Linux Conventions du noyau" du supplément du processeur d'architecture AMD64 de l'interface binaire d'application System V. Les dernières versions des psABI i386 et x86-64 System V peuvent être trouvées à partir de cette page dans le référentiel du responsable de l'ABI. liens ABI à jour et beaucoup d'autres bonnes choses sur x86 asm.)
Voici l'extrait de cette section :
- Les applications de niveau utilisateur utilisent des registres d'entiers pour transmettre la séquence %rdi, %rsi, %rdx, %rcx,%r8 et %r9. L'interface du noyau utilise %rdi, %rsi, %rdx, %r10, %r8 et %r9.
- Un appel système est effectué via le
syscall
consigne . Cela écrase %rcx et %r11 ainsi que la valeur de retour %rax, mais les autres registres sont préservés.- Le numéro du syscall doit être passé dans le registre %rax.
- Les appels système sont limités à six arguments, aucun argument n'est transmis directement sur la pile.
- De retour de l'appel système, le registre %rax contient le résultat de l'appel système. Une valeur comprise entre -4095 et -1 indique une erreur, c'est
-errno
.- Seules les valeurs de la classe INTEGER ou de la classe MEMORY sont transmises au noyau.
N'oubliez pas que cela provient de l'annexe spécifique à Linux de l'ABI, et même pour Linux, c'est informatif et non normatif. (Mais c'est en fait exact.)
Ce int $0x80
32 bits ABI est utilisable en code 64 bits (mais fortement déconseillé). Que se passe-t-il si vous utilisez l'ABI Linux int 0x80 32 bits dans du code 64 bits ? Il tronque toujours ses entrées en 32 bits, il n'est donc pas adapté aux pointeurs et il met à zéro r8-r11.
Interface utilisateur :appel de fonction
Convention d'appel de fonction x86-32 :
Dans x86-32, les paramètres étaient passés sur la pile. Le dernier paramètre a été poussé en premier sur la pile jusqu'à ce que tous les paramètres soient définis, puis call
l'instruction a été exécutée. Ceci est utilisé pour appeler les fonctions de la bibliothèque C (libc) sous Linux à partir de l'assembly.
Les versions modernes de l'ABI i386 System V (utilisé sur Linux) nécessitent un alignement sur 16 octets de %esp
avant un call
, comme l'ABI x86-64 System V l'a toujours exigé. Les appelés sont autorisés à supposer cela et à utiliser les chargements/stockages SSE 16 octets qui échouent sur non aligné. Mais historiquement, Linux ne nécessitait qu'un alignement de pile de 4 octets, il fallait donc un travail supplémentaire pour réserver un espace naturellement aligné même pour un double
de 8 octets. ou quelque chose.
Certains autres systèmes 32 bits modernes ne nécessitent toujours pas un alignement de pile de plus de 4 octets.
Convention d'appel des fonctions de l'espace utilisateur x86-64 System V :
x86-64 System V transmet les arguments dans les registres, ce qui est plus efficace que la convention d'args de pile de i386 System V. Cela évite la latence et les instructions supplémentaires de stockage des arguments en mémoire (cache) puis de les recharger dans l'appelé. Cela fonctionne bien car il y a plus de registres disponibles et convient mieux aux processeurs hautes performances modernes où la latence et l'exécution dans le désordre sont importantes. (L'ABI i386 est très ancienne).
Dans ce nouveau mécanisme :d'abord, les paramètres sont divisés en classes. La classe de chaque paramètre détermine la manière dont il est passé à la fonction appelée.
Pour des informations complètes, reportez-vous à : "3.2 Function Calling Sequence" du System V Application Binary Interface AMD64 Architecture Processor Supplement qui lit, en partie :
Une fois les arguments classés, les registres sont assignés (dans l'ordre de gauche à droite) pour passer comme suit :
- Si la classe est MEMORY, passez l'argument sur la pile.
- Si la classe est INTEGER, le prochain registre disponible de la séquence %rdi, %rsi, %rdx, %rcx, %r8 et %r9 est utilisé
Alors %rdi, %rsi, %rdx, %rcx, %r8 and %r9
les registres sont-ils en ordre utilisé pour passer des paramètres d'entier/pointeur (c'est-à-dire de classe INTEGER) à n'importe quelle fonction libc depuis l'assembly. %rdi est utilisé pour le premier paramètre INTEGER. %rsi pour le 2ème, %rdx pour le 3ème et ainsi de suite. Puis call
l'instruction doit être donnée. La pile (%rsp
) doit être aligné en 16B lorsque call
s'exécute.
S'il y a plus de 6 paramètres INTEGER, le 7e paramètre INTEGER et les suivants sont transmis sur la pile. (L'appelant apparaît, comme x86-32.)
Les 8 premiers arguments en virgule flottante sont passés dans %xmm0-7, plus tard sur la pile. Il n'y a pas de registres vectoriels à appel préservé. (Une fonction avec un mélange d'arguments FP et entiers peut avoir plus de 8 arguments de registre au total.)
Fonctions variadiques (comme printf
) toujours besoin de %al
=le nombre d'arguments de registre FP.
Il existe des règles pour savoir quand regrouper des structures dans des registres (rdx:rax
au retour) vs. en mémoire. Consultez l'ABI pour plus de détails et vérifiez la sortie du compilateur pour vous assurer que votre code est en accord avec les compilateurs sur la façon dont quelque chose doit être transmis/renvoyé.
Notez que la convention d'appel de fonction Windows x64 présente plusieurs différences significatives par rapport à x86-64 System V, comme l'espace fantôme qui doit être réservé par l'appelant (au lieu d'une zone rouge), et l'appel préservé xmm6-xmm15. Et des règles très différentes pour quel arg va dans quel registre.
Peut-être recherchez-vous l'ABI x86_64 ?
- www.x86-64.org/documentation/abi.pdf (404 at 2018-11-24)
- www.x86-64.org/documentation/abi.pdf (via Wayback Machine au 2018-11-24)
- Où est documentée l'ABI x86-64 System V ? - https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI est tenu à jour (par HJ Lu, l'un des mainteneurs d'ABI) avec des liens vers les PDF de la version officielle actuelle.
Si ce n'est pas exactement ce que vous recherchez, utilisez "x86_64 abi" dans votre moteur de recherche préféré pour trouver des références alternatives.
Les conventions d'appel définissent la manière dont les paramètres sont passés dans les registres lors de l'appel ou de l'appel par un autre programme. Et la meilleure source de ces conventions se présente sous la forme de normes ABI définies pour chacun de ces matériels. Pour faciliter la compilation, le même ABI est également utilisé par l'espace utilisateur et le programme du noyau. Linux/Freebsd suivent le même ABI pour x86-64 et un autre ensemble pour 32 bits. Mais x86-64 ABI pour Windows est différent de Linux/FreeBSD. Et généralement, ABI ne différencie pas l'appel système des "appels de fonctions" normaux. Par exemple, voici un exemple particulier de conventions d'appel x86_64 et c'est la même chose pour l'espace utilisateur Linux et le noyau :http://eli.thegreenplace.net/2011/ 09/06/stack-frame-layout-on-x86-64/ (notez la séquence a,b,c,d,e,f des paramètres) :
La performance est l'une des raisons de ces ABI (par exemple, passer des paramètres via des registres au lieu de les enregistrer dans des piles de mémoire)
Pour ARM, il existe plusieurs ABI :
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.swdev.abi/index.html
https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/iPhoneOSABIReference.pdf
Convention ARM64 :
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
Pour Linux sur PowerPC :
http://refspecs.freestandards.org/elf/elfspec_ppc.pdf
http://www.0x04.net/doc/elf/psABI-ppc64.pdf
Et pour l'embarqué il y a le PPC EABI :
http://www.freescale.com/files/32bit/doc/app_note/PPCEABI.pdf
Ce document est un bon aperçu de toutes les différentes conventions :
http://www.agner.org/optimize/calling_conventions.pdf