Ulteriori letture per uno qualsiasi degli argomenti qui: La guida definitiva alle chiamate di sistema di Linux
Ho verificato questi usando GNU Assembler (gas) su Linux.
Interfaccia del kernel
x86-32 aka convenzione i386 Linux System Call:
In x86-32 i parametri per la chiamata di sistema Linux vengono passati usando i registri. %eax
per syscall_number. % ebx,% ecx,% edx,% esi,% edi,% ebp sono usati per passare 6 parametri alle chiamate di sistema.
Il valore restituito è in %eax
. Tutti gli altri registri (incluso EFLAGS) sono conservati in tutto il int $0x80
.
Ho preso il seguente frammento dal Linux Assembly Tutorial ma ne dubito. Se qualcuno può mostrare un esempio, sarebbe fantastico.
Se sono presenti più di sei argomenti,
%ebx
deve contenere la posizione di memoria in cui è memorizzato l'elenco degli argomenti, ma non preoccuparti perché è improbabile che utilizzerai una syscall con più di sei argomenti.
Per un esempio e un po 'più di lettura, consultare http://www.int80h.org/bsdasm/#alternate-calling-convention . Un altro esempio di Hello World per Linux i386 con int 0x80
: Hello, mondo in linguaggio assembly con chiamate di sistema Linux?
Esiste un modo più veloce per effettuare chiamate di sistema a 32 bit: utilizzando sysenter
. Il kernel mappa una pagina di memoria in ogni processo (il vDSO), con il lato spazio utente della sysenter
danza, che deve cooperare con il kernel per poter trovare l'indirizzo di ritorno. Arg per registrare il mapping è lo stesso di int $0x80
. Dovresti normalmente chiamare in vDSO invece di usarlo sysenter
direttamente. (Consultare la Guida definitiva alle chiamate di sistema Linux per informazioni su collegamento e chiamata a vDSO e per ulteriori informazioni su sysenter
e tutto ciò che riguarda le chiamate di sistema.)
x86-32 [Free | Open | Net | DragonFly] Convenzione di chiamata di sistema BSD UNIX:
I parametri vengono passati sullo stack. Inserire i parametri (ultimo parametro inserito per primo) nello stack. Quindi inviare un ulteriore 32-bit di dati fittizi (i suoi dati non sono effettivamente fittizi. Fare riferimento al seguente link per ulteriori informazioni) e quindi dare un'istruzione di chiamata di sistemaint $0x80
http://www.int80h.org/bsdasm/#default-calling-convention
x86-64 Convenzione per chiamate di sistema Linux:
x86-64 Mac OS X è simile ma diverso . TODO: controlla cosa fa * BSD.
Fare riferimento alla sezione: "A.2 AMD64 Linux Kernel Convenzioni" di System V Application Binary Interface AMD64 architettura del processore Supplement . Le ultime versioni degli psabi System V i386 e x86-64 sono reperibili collegati da questa pagina nel repository del manutentore ABI . (Vedi anche ilX 86 tag wiki per collegamenti ABI aggiornati e molte altre cose utili su x86 asm.)
Ecco lo snippet di questa sezione:
- Le applicazioni a livello di utente utilizzano come registri interi per il passaggio della sequenza% rdi,% rsi,% rdx,% rcx,% r8 e% r9. L'interfaccia del kernel utilizza% rdi,% rsi,% rdx,% r10,% r8 e% r9.
- Una chiamata di sistema viene eseguita tramite l'
syscall
istruzione . Ciò blocca% rcx e% r11 nonché il valore di ritorno% rax, ma vengono conservati altri registri.
- Il numero della syscall deve essere passato nel registro% rax.
- Le chiamate di sistema sono limitate a sei argomenti, nessun argomento viene passato direttamente nello stack.
- Di ritorno dalla syscall, il registro% rax contiene il risultato della chiamata di sistema. Un valore compreso tra -4095 e -1 indica un errore, lo è
-errno
.
- Solo i valori della classe INTEGER o della classe MEMORY vengono passati al kernel.
Ricorda che questo proviene dall'appendice specifica di Linux all'ABI e anche per Linux è informativo non normativo. (Ma in realtà è accurato.)
Questa int $0x80
ABI a 32 bit è utilizzabile nel codice a 64 bit (ma altamente sconsigliata). Cosa succede se si utilizza l'ABI Linux 0x80 int a 32 bit nel codice a 64 bit? Tronca ancora i suoi input a 32 bit, quindi non è adatto per i puntatori e zeri r8-r11.
Interfaccia utente: chiamata di funzione
x86-32 Convenzione per la chiamata di funzioni:
In x86-32 i parametri sono stati passati in pila. L'ultimo parametro è stato prima inserito nello stack fino a quando non sono stati eseguiti tutti i parametri e quindi è call
stata eseguita l'istruzione. Questo è usato per chiamare le funzioni della libreria C (libc) su Linux dall'assembly.
Le versioni moderne dell'ABI System V i386 (usato su Linux) richiedono un allineamento di 16 byte di %esp
prima di un call
, come l'ABI System V x86-64 ha sempre richiesto. I Calle sono autorizzati ad assumerlo e utilizzano i carichi / archivi SSE a 16 byte che presentano guasti non allineati. Ma storicamente, Linux ha richiesto solo un allineamento dello stack di 4 byte, quindi ci è voluto un lavoro extra per riservare spazio allineato naturalmente anche per un 8 byte double
o qualcosa del genere.
Alcuni altri moderni sistemi a 32 bit non richiedono ancora un allineamento dello stack superiore a 4 byte.
x86-64 Sistema V convenzione spazio utente convenzione di chiamata:
x86-64 System V passa args nei registri, che è più efficiente della convenzione stack args di i386 System V. Evita la latenza e le istruzioni aggiuntive per la memorizzazione di args nella memoria (cache) e quindi il loro caricamento di nuovo nella chiamata. Funziona bene perché ci sono più registri disponibili ed è meglio per le moderne CPU ad alte prestazioni in cui sono importanti latenza ed esecuzione fuori servizio. (L'i386 ABI è molto vecchio).
In questo nuovo meccanismo: in primo luogo i parametri sono divisi in classi. La classe di ciascun parametro determina il modo in cui viene passato alla funzione chiamata.
Per informazioni complete, consultare: "3.2 Sequenza di chiamata delle funzioni" del supplemento al processore dell'architettura AMD64 per l'interfaccia binaria dell'applicazione System V che legge, in parte:
Una volta classificati gli argomenti, i registri vengono assegnati (nell'ordine da sinistra a destra) per passare come segue:
- Se la classe è MEMORY, passa l'argomento nello stack.
- Se la classe è INTEGER, viene utilizzato il successivo registro disponibile della sequenza% rdi,% rsi,% rdx,% rcx,% r8 e% r9
Così %rdi, %rsi, %rdx, %rcx, %r8 and %r9
sono i registri al fine utilizzati per passare interi / puntatore (cioè classe INTEGER) parametri di qualsiasi funzione libc da assemblaggio. % rdi viene utilizzato per il primo parametro INTEGER. % rsi per il 2 °,% rdx per il 3 ° e così via. Quindi call
dovrebbero essere fornite le istruzioni. Lo stack ( %rsp
) deve essere allineato a 16B quando call
viene eseguito.
Se sono presenti più di 6 parametri INTEGER, il settimo parametro INTEGER e successivi vengono passati sullo stack. (Il chiamante si apre, lo stesso di x86-32.)
I primi 8 arg in virgola mobile vengono passati in% xmm0-7, successivamente nello stack. Non ci sono registri vettoriali conservati per le chiamate. (Una funzione con una combinazione di argomenti FP e argomenti interi può avere più di 8 argomenti di registro totali.)
Le funzioni variabili ( comeprintf
) necessitano sempre %al
= il numero di argomenti del registro FP.
Ci sono regole per quando comprimere 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 sia d'accordo con i compilatori su come dovrebbe essere passato / restituito qualcosa.
Si noti che la convenzione di chiamata della funzione x64 di Windows presenta molte differenze significative rispetto al sistema V x86-64, come lo spazio ombra che deve essere riservato dal chiamante (anziché una zona rossa) e xmm6-xmm15 preservato dalla chiamata. E regole molto diverse per cui arg va in quale registro.