Les liens suivants expliquent les conventions d'appel système x86-32 pour UNIX (saveur BSD) et Linux:
Mais quelles sont les conventions d'appel système x86-64 sous UNIX et Linux?
Les liens suivants expliquent les conventions d'appel système x86-32 pour UNIX (saveur BSD) et Linux:
Mais quelles sont les conventions d'appel système x86-64 sous UNIX et Linux?
sysret
fonctionne, et rax est remplacé par la valeur de retour. Tous les autres registres sont conservés sur amd64.Réponses:
Lectures complémentaires pour l'un des sujets ici: Le guide définitif des appels système Linux
J'ai vérifié ces derniers en utilisant GNU Assembler (gas) sous Linux.
Interface du noyau
Convention d'appel système Linux x86-32 aka i386:
Dans x86-32, les paramètres pour l'appel système Linux sont passés à 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 dans
%eax
. Tous les autres registres (y compris EFLAGS) sont conservés dans leint $0x80
.J'ai pris l'extrait suivant du tutoriel d'assemblage Linux, mais j'en doute. Si quelqu'un peut montrer un exemple, ce serait formidable.
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
: Hello, world en langage assembleur avec des appels système Linux?Il existe un moyen plus rapide de passer des appels système 32 bits: utiliser
sysenter
. Le noyau mappe une page de mémoire dans chaque processus (le vDSO), avec le côté espace utilisateur de lasysenter
danse, 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 pourint $0x80
. Vous devez normalement appeler le vDSO au lieu d'utilisersysenter
directement. (Voir The Definitive Guide to Linux System Calls pour plus d'informations sur la liaison et l'appel dans le vDSO, et pour plus d'informations sursysenter
, et tout ce qui concerne les appels système.)x86-32 [Free | Open | Net | DragonFly] Convention d'appel système BSD UNIX:
Les paramètres sont passés sur la pile. Poussez les paramètres (le dernier paramètre poussé en premier) sur la pile. Ensuite, envoyez 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:
x86-64 Mac OS X est similaire mais différent . TODO: vérifiez ce que fait * BSD.
Reportez - vous à la section: "A.2 AMD64 Linux Conventions du noyau" du système binaire d' application V Interface Architecture AMD64 Supplément processeur . Les dernières versions des psABI i386 et x86-64 System V peuvent être trouvées liées à partir de cette page dans le repo du responsable ABI . (Voir aussi lex86 tag wiki pour les liens ABI à jour et beaucoup d'autres bonnes choses sur x86 asm.)
Voici l'extrait de cette section:
Rappelez-vous 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.)
Cet
int $0x80
ABI 32 bits 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 un code 64 bits? Il tronque toujours ses entrées en 32 bits, il ne convient donc pas aux pointeurs et 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 terminés, puis l'
call
instruction a été exécutée. Ceci est utilisé pour appeler les fonctions de la bibliothèque C (libc) sur Linux à partir de l'assembly.Les versions modernes de l'ABI i386 System V (utilisé sous Linux) nécessitent un alignement de 16 octets
%esp
avant acall
, comme l'ABI System V x86-64 l'a toujours exigé. Les appelées sont autorisés à supposer que et à utiliser les charges / 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 8 octetsdouble
ou quelque chose du genre.Certains autres systèmes 32 bits modernes ne nécessitent toujours pas d'alignement de pile de plus de 4 octets.
x86-64 System V espace utilisateur Fonction Convention d'appel:
x86-64 System V passe les arguments dans les registres, ce qui est plus efficace que la convention d'arguments de pile d'i386 System V. Cela évite la latence et les instructions supplémentaires de stockage des arguments en mémoire (cache), puis de les charger à nouveau dans l'appelé. Cela fonctionne bien car il y a plus de registres disponibles et c'est mieux pour les processeurs modernes hautes performances où la latence et l'exécution dans le désordre sont importantes. (Le i386 ABI est très ancien).
Dans ce nouveau mécanisme: Premièrement, 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 supplément de processeur d'architecture AMD64 de l'interface binaire d'application System V qui lit, en partie:
Ainsi ,
%rdi, %rsi, %rdx, %rcx, %r8 and %r9
les registres de commande utilisés pour transmettre entier / pointeur paramètres ( par exemple classe INTEGER) à toute fonction libc de montage. % rdi est utilisé pour le premier paramètre INTEGER. % rsi pour le 2ème,% rdx pour le 3ème et ainsi de suite. Ensuite, descall
instructions devraient être données. La pile (%rsp
) doit être alignée sur 16B lors de l'call
exécution.S'il y a plus de 6 paramètres INTEGER, le 7ème paramètre INTEGER et les suivants sont passés sur la pile. (L'appelant apparaît, identique à x86-32.)
Les 8 premiers arguments à virgule flottante sont passés dans% xmm0-7, plus tard sur la pile. Il n'y a pas de registres vectoriels préservés des appels. (Une fonction avec un mélange d'arguments FP et entiers peut avoir plus de 8 arguments de registre au total.)
Les fonctions variadiques ( comme
printf
) ont toujours besoin%al
du nombre d'arguments du registre FP.Il existe des règles pour conditionner les structures dans des registres (
rdx:rax
au retour) ou 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 d'accord avec les compilateurs sur la manière dont quelque chose doit être transmis / retourné.Notez que la convention d'appel de la fonction Windows x64 présente plusieurs différences significatives par rapport au système x86-64 System V, comme l'espace d'ombre 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 lesquelles arg va dans quel registre.
la source
int 0x80
ABI de Linux dans un code 64 bits, c'est exactement ce qui se passe: stackoverflow.com/questions/46087730/… . Il met à zéro r8-r11 et fonctionne exactement comme lorsqu'il est exécuté dans un processus 32 bits. Dans ce Q&A, j'ai un exemple montrant qu'il fonctionne ou échoue avec la troncature d'un pointeur. Et j'ai aussi fouillé dans la source du noyau pour montrer pourquoi il se comporte de cette façon.Peut-être cherchez-vous l'ABI x86_64?
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.
la source
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 d'un autre programme. Et la meilleure source de ces conventions se trouve 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 les appels système des "appels de fonctions" normaux. C'est à dire, voici un exemple particulier de conventions d'appel x86_64 et il en va de même 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):
Les performances sont 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 différents 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 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
la source
Commentaires sur les sources du noyau Linux 5.0
Je savais que les spécificités de x86 sont sous
arch/x86
, et que les trucs syscall passent sousarch/x86/entry
. Donc un rapidegit grep rdi
dans ce répertoire m'amène à arch / x86 / entry / entry_64.S :et pour 32 bits à arch / x86 / entry / entry_32.S :
glibc 2.29 implémentation des appels système Linux x86_64
Trichons maintenant en examinant les implémentations majeures de la libc et voyons ce qu'elles font.
Quoi de mieux que de regarder dans la glibc que j'utilise actuellement au moment où j'écris cette réponse? :-)
la glibc 2.29 définit les appels système x86_64 à
sysdeps/unix/sysv/linux/x86_64/sysdep.h
et qui contient du code intéressant, par exemple:et:
qui, à mon avis, sont assez explicites. Notez comment cela semble avoir été conçu pour correspondre exactement à la convention d'appel des fonctions ABI AMD64 standard du système V: https://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions
Rappel rapide des clobbers:
cc
signifie registres de drapeaux. Mais Peter Cordes commente que ce n'est pas nécessaire ici.memory
signifie qu'un pointeur peut être passé dans l'assembly et utilisé pour accéder à la mémoirePour un exemple explicite minimal exécutable à partir de zéro, consultez cette réponse: Comment invoquer un appel système via sysenter dans l'assembly en ligne?
Effectuer manuellement des appels système dans l'assemblage
Pas très scientifique, mais amusant:
x86_64.S
GitHub en amont .
aarch64
J'ai montré un exemple utilisateur minimal exécutable à l' adresse : /reverseengineering/16917/arm64-syscalls-table/18834#18834 Le code du noyau grep TODO ici, devrait être facile.
la source
"cc"
clobber n'est pas nécessaire: les appels système Linux sauvegardent / restaurent RFLAGS (Les instructionssyscall
/ lesysret
font en utilisant R11, et le noyau ne modifie pas le R11 / RFLAGS enregistré autrement que via desptrace
appels système du débogueur.) Pas que cela compte jamais, car un"cc"
clobber est implicite pour x86 / x86-64 dans GNU C Extended asm, vous ne pouvez donc rien gagner en l'omettant.