Quelles sont les conventions d'appel pour le système UNIX et Linux invite i386 et x86-64
Question
Après des liens expliquent x86-32 conventions d'appel du système pour les UNIX (BSD saveur) et Linux:
Mais quelles sont les conventions d'appel du système x86-64 sur UNIX et Linux à la fois?
La solution
Pour en savoir plus pour l'un des sujets ici: Le Guide définitif à Linux appels système
Je vérifiais ces utilisant GNU Assembleur (gaz) sous Linux.
Interface noyau
x86-32 alias i386 convention Linux Système d'appel:
Dans les paramètres pour x86-32 appel système Linux sont transmis à l'aide des registres. %eax
pour syscall_number. % Ebx, ecx%,% edx,% esi,% edi,% ebp sont utilisés pour faire passer des paramètres à 6 appels système.
La valeur de retour est en %eax
. Tous les autres registres (y compris EFLAGS) sont conservés pour les int $0x80
.
Je pris l'extrait suivant de Linux Tutoriel Assemblée mais je doute à ce sujet. Si l'on peut montrer un exemple, ce serait formidable.
S'il y a plus de six arguments,
%ebx
doit contenir la mémoire endroit où la liste des arguments est stocké - mais ne vous inquiétez pas à ce sujet car il est peu probable que vous utiliserez un syscall 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 d'un Bonjour tout le monde pour Linux i386 en utilisant int 0x80
: Quelles parties de ce code d'assemblage HelloWorld sont essentiels si je devais écrire le programme dans l'assemblage?
Il y a une façon plus rapide de rendre le système 32 bits appels: en utilisant sysenter
. Le noyau mappe une page de mémoire dans tous les processus (le vDSO), avec le côté de l'espace utilisateur de la danse sysenter
, qui doit coopérer avec le noyau pour qu'il soit en mesure de trouver l'adresse de retour. Arg au registre cartographie est le même que pour int $0x80
. Vous devriez normalement appeler dans le vDSO au lieu d'utiliser directement sysenter
. (Voir Definitive Guide to Linux appels système pour plus d'informations sur la liaison et la remise en vDSO, et pour plus d'informations sur sysenter
, et tout le reste à faire avec des appels système.)
x86-32 [gratuit | Open | Net | DragonFly] BSD UNIX convention Système d'appel:
Les paramètres sont passés sur la pile. Appuyez sur les paramètres (dernier paramètre poussé en premier) sur la pile. Appuyez ensuite sur un 32 bits supplémentaire de données fictives (Ses pas réellement des données fictives. Consultez lien suivant pour plus d'informations), puis donner une instruction appel système int $0x80
http://www.int80h.org/bsdasm/#default-calling- convention
Linux x86-64 Système convention d'appel:
x86-64 Mac OS X est similaire, mais différent . TODO:. * BSD vérifier ce que fait
Reportez-vous à la section: "A.2 AMD64 Linux Conventions de noyau" de System V application Binary Interface architecture AMD64 Supplément processeur . Les dernières versions des i386 et x86-64 système V psABIs se trouvent liés à partir de cette page repo du mainteneur ABI. (Voir aussi la x86 wiki de balise pour la mise à jour des liens ABI et beaucoup d'autres bonnes choses à propos de x86 asm.)
Voici l'extrait de cette section:
- applications de niveau utilisateur utilisent comme des registres entiers pour faire passer le séquence rdi%,% rsi, rdx%,% rcx, % R8 et r9%. L'interface du noyau utilise% rdi,% rsi,% RDX,% r10,% r8 et r9%.
- Un système d'appel se fait via le instruction
syscall
. Cette aplatit % RCX et% r11 ainsi que le% rax valeur de retour, mais d'autres registres sont conservés.- Le nombre de syscall doit être passée dans le registre% rax.
- System-appels sont limités à six arguments, aucun argument est passé directement sur la pile.
- De retour de la syscall, inscrivez-% rax contient le résultat de le système d'appel. Une valeur comprise entre -4095 et -1 indique une erreur, il est
-errno
.- Seules les valeurs de mémoire ENTIER de classe ou en classe sont transmises au noyau.
Rappelez-vous ceci est de l'annexe spécifique à Linux à l'ABI, et même pour Linux, il est instructif non normatif. (Mais il est en fait exact.)
32 bits int $0x80
ABI est utilisable dans le code 64 bits (mais très non recommandé). Qu'advient-il si vous utilisez la version 32 bits int 0x80 Linux ABI dans le code 64 bits? il tronque encore ses entrées à 32 bits, il est donc inadapté pour les pointeurs, et remet à zéro r8-r11.
Interface utilisateur: fonction d'appel
Fonction x86-32 Convention d'appel:
Dans les paramètres x86-32 ont été passés sur la pile. Le dernier paramètre a été poussé d'abord à la pile jusqu'à ce que tous les paramètres sont effectués et l'instruction call
a été exécuté. Il est utilisé pour appeler des fonctions de bibliothèque C (libc) sur Linux de l'assemblage.
Les versions modernes du système i386 V ABI (utilisé sous Linux) exigent un alignement de 16 octets de %esp
devant un call
, comme le x86-64 System V ABI a toujours nécessaire. Sont autorisés à fonctions appelées supposer que et utiliser SSE des charges de 16 octets / magasins que la faute non alignés. Mais historiquement, Linux uniquement nécessaire alignement de la pile de 4 octets, donc il a fallu un travail supplémentaire pour réserver un espace naturellement aligné même pour un double
8 octets ou quelque chose.
D'autres systèmes 32 bits modernes ne nécessitent pas encore plus de 4 octets alignement de la pile.
x86-64 système V-espace utilisateur Fonction La convention d'appel:
x86-64 System V passe args dans les registres, ce qui est plus efficace que la convention args pile de système i386 V. Il évite les temps d'attente et des instructions supplémentaires de stockage args à la mémoire (cache), puis de les charger à nouveau dans le callee. Cela fonctionne bien parce qu'il ya plus de registres disponibles, et il est préférable pour les processeurs modernes de haute performance où la latence et hors ordre matière d'exécution. (Le i386 ABI 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 elle est transmise à la fonction appelée.
Pour plus d'informations reportez-vous à: "3.2 Fonction Séquence d'appel" de System V application Binary Interface architecture AMD64 Les Supplément de processeur qui se lit, en partie:
Une fois que les arguments sont classés, les registres sont-ils assignés (en de gauche à droite commande) pour le passage de la manière suivante:
- Si la classe est MEMORY, passer l'argument sur la pile.
- Si la classe est ENTIER, la prochaine dispositible du registre séquence rdi%,% rsi, rdx%,% rcx,% r8 et r9% est utilisé
%rdi, %rsi, %rdx, %rcx, %r8 and %r9
sont les registres pour utilisé pour transmettre des paramètres entier / pointeur (par exemple de classe INTEGER) à toute fonction libc de montage. % Rdi est utilisé pour le premier paramètre entier. % rsi pour 2%, RDX pour la 3e et ainsi de suite. Ensuite, l'instruction de call
doit être donnée. L'empilement (%rsp
) doit être aligné 16B lorsque call
exécute.
S'il y a plus de 6 paramètres Integer, le paramètre 7 ENTIER puis sont passés sur la pile. (Pops appelant, même que x86-32.)
Les 8 premières virgule flottante args sont passés en% xmm0-7, plus tard sur la pile. Il n'y a pas de registres vectoriels appel conservés. (Une fonction avec un mélange d'arguments de PF et entières peuvent avoir plus de 8 arguments de registres totaux).
Fonctions VARIADIC ( comme printf
) toujours besoin %al
= le nombre de args de registre FP.
Il y a des règles pour quand emballer struct dans les registres (rdx:rax
sur le retour) par rapport à la mémoire. Voir l'ABI pour plus de détails et vérifier la sortie du compilateur pour vous assurer que votre code est d'accord avec les compilateurs sur la façon dont quelque chose doit être passé / retour.
Notez que la fonction Windows x64 appelant convention a plusieurs différences importantes par rapport x86-64 System V, comme l'espace d'ombre que doit être réservé par l'appelant (au lieu d'une zone rouge), et appelez-Cuit xmm6-xmm15 . Et des règles très différentes pour lesquelles arg va dans quel registre.
Autres conseils
Peut-être que vous cherchez le x86_64 ABI?
- www.x86-64.org/documentation/abi.pdf (404 à 24.11.2018)
- www.x86-64.org /documentation/abi.pdf (via Wayback machine à 24/11/2018)
- Où est le système x86-64 V ABI documenté? - https://github.com/hjl-tools / x86-psABI / wiki / x86-psABI est tenue à jour (par HJ Lu, l'un des mainteneurs ABI) avec des liens vers des fichiers PDF de la version actuelle officielle.
Si ce n'est pas exactement ce que vous êtes après, utilisez « x86_64 abi » dans votre moteur de recherche préféré pour trouver d'autres références.
Conventions d'appel définit la façon dont les paramètres sont passés dans les registres lors de l'appel ou d'être appelé par un autre programme. Et la meilleure source de ces conventions est sous 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 programme du noyau. Linux / Freebsd suivent le même ABI pour x86-64 et un autre ensemble pour les 32 bits. Mais x86-64 ABI pour Windows est différent de Linux / FreeBSD. Et généralement ABI ne différencie pas appel système vs « appels de fonctions » normales. -À-dire, voici un exemple particulier de conventions d'appel x86_64 et il est le même pour Linux et le noyau userspace: http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/ (notez la séquence d'un , b, c, d, e, f de paramètres):
La performance est l'une des raisons de ces ABI (par exemple, les paramètres en passant par les registres au lieu d'enregistrer en piles de mémoire)
Pour ARM il y a plusieurs ABI:
http : //infocenter.arm.com/help/index.jsp topic = / com.arm.doc.subset.swdev.abi / index.html
convention ARM64:
http://infocenter.arm.com/ Aide / sujet / 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 intégré il y a le PPC EABI:
http://www.freescale.com/files/32bit/ doc / app_note / PPCEABI.pdf
Ce document est bonne vue d'ensemble de toutes les différentes conventions:
noyau Linux 5.0 commentaires source
Je savais que les détails x86 sont sous arch/x86
, et ce genre de choses syscall passe sous arch/x86/entry
. Ainsi, un git grep rdi
rapide dans ce répertoire me conduit à arch / x86 / entrée / entry_32.S :
/*
* 32-bit SYSENTER entry.
*
* 32-bit system calls through the vDSO's __kernel_vsyscall enter here
* if X86_FEATURE_SEP is available. This is the preferred system call
* entry on 32-bit systems.
*
* The SYSENTER instruction, in principle, should *only* occur in the
* vDSO. In practice, a small number of Android devices were shipped
* with a copy of Bionic that inlined a SYSENTER instruction. This
* never happened in any of Google's Bionic versions -- it only happened
* in a narrow range of Intel-provided versions.
*
* SYSENTER loads SS, ESP, CS, and EIP from previously programmed MSRs.
* IF and VM in RFLAGS are cleared (IOW: interrupts are off).
* SYSENTER does not save anything on the stack,
* and does not save old EIP (!!!), ESP, or EFLAGS.
*
* To avoid losing track of EFLAGS.VM (and thus potentially corrupting
* user and/or vm86 state), we explicitly disable the SYSENTER
* instruction in vm86 mode by reprogramming the MSRs.
*
* Arguments:
* eax system call number
* ebx arg1
* ecx arg2
* edx arg3
* esi arg4
* edi arg5
* ebp user stack
* 0(%ebp) arg6
*/
glibc 2.29 Linux mise en œuvre de l'appel système x86_64
Maintenant, nous allons tricher en regardant une des grandes implémentations libc et voir ce qu'ils font.
Quoi de mieux que de regarder dans la glibc que j'utilise en ce moment que je vous écris cette réponse? : -)
2,29 glibc définit syscalls x86_64 à sysdeps/unix/sysv/linux/x86_64/sysdep.h
et qui contient un code intéressant, par exemple:
/* The Linux/x86-64 kernel expects the system call parameters in
registers according to the following table:
syscall number rax
arg 1 rdi
arg 2 rsi
arg 3 rdx
arg 4 r10
arg 5 r8
arg 6 r9
The Linux kernel uses and destroys internally these registers:
return address from
syscall rcx
eflags from syscall r11
Normal function call, including calls to the system call stub
functions in the libc, get the first six parameters passed in
registers and the seventh parameter and later on the stack. The
register use is as follows:
system call number in the DO_CALL macro
arg 1 rdi
arg 2 rsi
arg 3 rdx
arg 4 rcx
arg 5 r8
arg 6 r9
We have to take care that the stack is aligned to 16 bytes. When
called the stack is not aligned since the return address has just
been pushed.
Syscalls of more than 6 arguments are not supported. */
et
/* Registers clobbered by syscall. */
# define REGISTERS_CLOBBERED_BY_SYSCALL "cc", "r11", "cx"
#undef internal_syscall6
#define internal_syscall6(number, err, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
unsigned long int resultvar; \
TYPEFY (arg6, __arg6) = ARGIFY (arg6); \
TYPEFY (arg5, __arg5) = ARGIFY (arg5); \
TYPEFY (arg4, __arg4) = ARGIFY (arg4); \
TYPEFY (arg3, __arg3) = ARGIFY (arg3); \
TYPEFY (arg2, __arg2) = ARGIFY (arg2); \
TYPEFY (arg1, __arg1) = ARGIFY (arg1); \
register TYPEFY (arg6, _a6) asm ("r9") = __arg6; \
register TYPEFY (arg5, _a5) asm ("r8") = __arg5; \
register TYPEFY (arg4, _a4) asm ("r10") = __arg4; \
register TYPEFY (arg3, _a3) asm ("rdx") = __arg3; \
register TYPEFY (arg2, _a2) asm ("rsi") = __arg2; \
register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \
asm volatile ( \
"syscall\n\t" \
: "=a" (resultvar) \
: "0" (number), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4), \
"r" (_a5), "r" (_a6) \
: "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \
(long int) resultvar; \
})
que je me sens sont assez explicites. Notez comment cela semble avoir été conçu pour correspondre exactement à la convention d'appel du système régulier des fonctions V AMD64 ABI: https://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions
rappel rapide des aplatit:
-
cc
signifie registres de drapeau. Mais Peter Cordes commentaires que ce n'est pas nécessaire ici. -
memory
signifie qu'un pointeur peut être passé dans l'assemblage et permet d'accéder à la mémoire
Pour un exemple explicite runnable minimale à partir de zéro voir cette réponse: Comment invoquer un appel système via sysenter en assembleur en ligne?
Faire quelques syscalls dans l'assemblage manuellement
Pas très scientifique, mais amusant:
-
x86_64.S
.text .global _start _start: asm_main_after_prologue: /* write */ mov $1, %rax /* syscall number */ mov $1, %rdi /* stdout */ mov $msg, %rsi /* buffer */ mov $len, %rdx /* len */ syscall /* exit */ mov $60, %rax /* syscall number */ mov $0, %rdi /* exit status */ syscall msg: .ascii "hello\n" len = . - msg
GitHub amont.
aarch64
Je l'ai montré un exemple userland runnable minimale à: https: // rétro-ingénierie. stackexchange.com/questions/16917/arm64-syscalls-table/18834#18834 TODO code noyau grep ici, devrait être facile.