Quali sono le convenzioni di chiamata per le chiamate di sistema UNIX e Linux su i386 e x86-64

I seguenti collegamenti spiegano le convenzioni di chiamata di sistema x86-32 sia per UNIX (flavor BSD) che per Linux:

Ma quali sono le convenzioni di chiamata di sistema x86-64 sia su UNIX che su Linux?

Li ho verificati usando GNU Assembler (gas) su Linux.

Interfaccia del kernel

convenzione di sistema x86-32 per le chiamate di sistema:

Nei parametri x86-32 per la chiamata di sistema Linux vengono passati utilizzando i registri. %eax per syscall_number. % ebx,% ecx,% edx,% esi,% edi,% ebp vengono utilizzati per passare 6 parametri alle chiamate di sistema.

Il valore di ritorno è in %eax . Tutti gli altri registri (tra cui EFLAGS) vengono mantenuti su Int int $0x80 .

Ho preso lo snippet seguente dal Linux Assembly Tutorial, ma ne dubito. Se qualcuno può mostrare un esempio, sarebbe fantastico.

Se ci sono più di sei argomenti, %ebx deve contenere il percorso di memoria in cui è archiviato l’elenco degli argomenti, ma non preoccuparti di ciò perché è improbabile che tu userai un syscall con più di sei argomenti.

Per un esempio e un po ‘più di lettura, consultare http://www.int80h.org/bsdasm/#alternate-calling-convention

C’è un modo più veloce per effettuare chiamate di sistema a 32 bit: usando sysenter . Il kernel mappa una pagina di memoria in ogni processo (il vdso), con il lato spazio utente del sysenter , che deve cooperare con il kernel affinché sia ​​in grado di trovare l’indirizzo di ritorno. arg per registrare la mapping è la stessa di int $0x80 , ma invece di quella istruzione, il codice dovrebbe chiamare una funzione nel vdso. (TODO: aggiorna questo con un link e / o informazioni specifiche).

x86-32 [Free | Open | Net | DragonFly] Convenzione di sistema BSD UNIX:

I parametri vengono passati in pila. Spingere i parametri (ultimo parametro premuto per primi) sulla pila. Quindi invia un ulteriore 32 bit di dati fittizi (in realtà non si tratta di dati fittizi. Fai riferimento al seguente link per ulteriori informazioni) e quindi fornisci un’istruzione di chiamata di sistema int $0x80

http://www.int80h.org/bsdasm/#default-calling-convention


convenzione di sistema x86-64 per Linux System:

x86-64 Mac OS X è simile ma diverso . TODO: controlla cosa fa * BSD.

Fare riferimento alla sezione: “A.2 Convenzioni del kernel Linux AMD64″ del Supplemento del processore di architettura AMD64 per l’interfaccia binaria di System V. Le versioni più recenti degli ps3 di System V i386 e x86-64 possono essere trovate collegate da questa pagina nel repository del manutentore ABI . (Vedi anche il wiki dei tag x86 per i link ABI aggiornati e molte altre cose interessanti su x86 asm.)

Ecco lo snippet di questa sezione:

  1. Le applicazioni a livello utente utilizzano come registri di numeri interi per passare la sequenza% rdi,% rsi,% rdx,% rcx,% r8 e% r9. L’interfaccia del kernel utilizza% rdi,% rsi,% rdx,% r10,% r8 e% r9.
  2. Una chiamata di sistema viene eseguita tramite l’ istruzione syscall . Questo clobbers% rcx e% r11, così come% rax, ma altri registri sono conservati.
  3. Il numero di syscall deve essere passato nel registro% rax.
  4. Le chiamate di sistema sono limitate a sei argomenti, nessun argomento viene passato direttamente nello stack.
  5. Tornando da syscall, il registro% rax contiene il risultato della chiamata di sistema. Un valore compreso tra -4095 e -1 indica un errore, è -errno .
  6. Solo i valori della class INTEGER o della class MEMORY vengono passati al kernel.

Ricorda che questo è dall’appendice specifica di Linux all’ABI, e anche per Linux è informativo non normativo. (Ma in realtà è accurato.)

Interfaccia utente

convenzione di chiamata della funzione x86-32:

Nei parametri x86-32 sono stati passati in pila. L’ultimo parametro è stato inserito prima nello stack fino a quando non sono stati completati tutti i parametri e quindi è stata eseguita l’istruzione di call . Questo è usato per chiamare le funzioni della libreria C (libc) su Linux dall’assemblaggio.


convenzione di chiamata della funzione x86-64:

x86-64 passa gli args nei registri, che è più efficiente della convenzione i386 System V dello stack arg. Evita la latenza e le istruzioni aggiuntive di archiviare gli argomenti in memoria (cache) e quindi li carica di nuovo nel callee. Funziona bene perché ci sono più registri disponibili, ed è meglio per le moderne CPU ad alte prestazioni in cui la latenza e l’esecuzione fuori dall’ordine sono importanti. (L’ABI i386 è molto vecchio).

In questo nuovo meccanismo: prima i parametri sono divisi in classi. La class di ciascun parametro determina il modo in cui viene passata alla funzione chiamata.

Per informazioni complete, consultare “3.2 Function Calling Sequence” di System V Application Interfaccia binaria AMD64 Processor Architecture Supplement che legge, in parte:

Una volta classificati gli argomenti, i registri vengono assegnati (in ordine da sinistra a destra) per il passaggio come segue:

  1. Se la class è MEMORIA, passa l’argomento in pila.
  2. Se la class è INTEGER, viene utilizzato il successivo registro disponibile della sequenza% rdi,% rsi,% rdx,% rcx,% r8 e% r9

Quindi %rdi, %rsi, %rdx, %rcx, %r8 and %r9 sono i registri in ordine usati per passare parametri interi / pointer (cioè class INTEGER) a qualsiasi funzione libc dall’assembly. % rdi è usato per il primo parametro INTEGER. % rsi per 2nd,% rdx per 3rd e così via. Quindi dovrebbero essere date istruzioni di call . Lo stack ( %rsp ) deve essere allineato a 16B quando viene eseguita la call .

Se sono presenti più di 6 parametri INTEGER, il 7 ° parametro INTEGER e successivamente vengono passati in pila. (Il chiamante si apre, come x86-32.)

I primi 8 argomenti in virgola mobile vengono passati in% xmm0-7, successivamente in pila. Non ci sono registri vettoriali preservati per le chiamate. (Una funzione con una combinazione di argomenti FP e interi può avere più di 8 argomenti di registro totali).

Le funzioni variabili ( come printf ) richiedono sempre %al = il numero di argomenti del registro FP.

Ci sono regole per quando impacchettare le strutture nei registri ( rdx:rax al ritorno) rispetto alla memoria. Vedi l’ABI per i dettagli e controlla l’output del compilatore per assicurarti che il tuo codice concorda con i compilatori su come qualcosa deve essere passato / restituito.

Forse stai cercando l’ABI x86_64?

Se non è esattamente quello che cerchi, usa ‘x86_64 abi’ nel tuo motore di ricerca preferito per trovare riferimenti alternativi.

Le convenzioni di chiamata definiscono come i parametri vengono passati nei registri quando chiamano o vengono chiamati da un altro programma. E la migliore fonte di queste convenzioni è sotto forma di standard ABI definiti per ciascun hardware. Per facilità di compilazione, lo stesso ABI è anche usato da userspace e dal programma del kernel. Linux / Freebsd seguono lo stesso ABI per x86-64 e un altro set per 32-bit. Ma l’ABI x86-64 per Windows è diverso da Linux / FreeBSD. E generalmente ABI non differenzia la chiamata di sistema rispetto alle normali “chiamate di funzioni”. Vale a dire, ecco un particolare esempio di convenzioni di chiamata x86_64 ed è lo stesso per entrambi gli userspace e kernel di Linux: http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64 / (nota la sequenza a, b, c, d, e, f dei parametri):

Un buon rendering dell'uso delle convenzioni di chiamata rispetto ai registri

Le prestazioni sono una delle ragioni di questi ABI (ad esempio, il passaggio di parametri tramite registri anziché il salvataggio in stack di memoria)

Per ARM ci sono vari 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

Convenzione ARM64:

http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf

Per Linux su PowerPC:

http://refspecs.freestandards.org/elf/elfspec_ppc.pdf

http://www.0x04.net/doc/elf/psABI-ppc64.pdf

E per embedded c’è l’EABI PPC:

http://www.freescale.com/files/32bit/doc/app_note/PPCEABI.pdf

Questo documento è una buona panoramica di tutte le diverse convenzioni:

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

Oltre al link che Jonathan Leffler fornisce nella sua risposta, anche il pdf di Convenzioni di chiamata di Agner Fog potrebbe esserti utile.