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?

Était-ce utile?

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 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:

  
      
  1. 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%.
  2.   
  3. 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.
  4.   
  5. Le nombre de syscall doit être passée dans le registre% rax.
  6.   
  7. System-appels sont limités à six arguments, aucun argument est passé   directement sur la pile.
  8.   
  9. 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.
  10.   
  11. Seules les valeurs de mémoire ENTIER de classe ou en classe sont transmises au noyau.
  12.   

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:

     
      
  1. Si la classe est MEMORY, passer l'argument sur la pile.
  2.   
  3. Si la classe est ENTIER, la prochaine dispositible du registre   séquence rdi%,% rsi, rdx%,% rcx,% r8 et r9% est utilisé
  4.   

%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?

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):

 Un bon rendu des conventions d'appel contre l'utilisation des registres

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

https://developer.apple.com/ bibliothèque / ios / documentation / Xcode / conceptuel / iPhoneOSABIReference / iPhoneOSABIReference.pdf

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:

http://www.agner.org/optimize/calling_conventions.pdf

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top