GNU/Linux >> Linux Esercitazione >  >> Linux

x86_64 Assembly Linux System Call Confusion

Molto è cambiato tra i386 e x86_64, incluse sia le istruzioni utilizzate per accedere al kernel sia i registri utilizzati per trasportare gli argomenti delle chiamate di sistema. Ecco il codice equivalente al tuo:

.section .data

.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rdi
syscall

Citando questa risposta a una domanda correlata:

I numeri delle chiamate di sistema si trovano nel codice sorgente di Linux in arch/x86/include/asm/unistd_64.h. Il numero di syscall viene passato nel registro rax. I parametri sono in rdi, rsi, rdx, r10, r8, r9. La chiamata viene richiamata con l'istruzione "syscall". La syscall sovrascrive il registro rcx. Il rendimento è in rax.


Stai riscontrando una differenza sorprendente tra i386 e x86_64:non usano lo stesso meccanismo di chiamata di sistema. Il codice corretto è:

movq $60, %rax
movq $2,  %rdi   ; not %rbx!
syscall

Interrompi 0x80 invoca sempre chiamate di sistema a 32 bit. Viene utilizzato per consentire l'esecuzione di applicazioni a 32 bit su sistemi a 64 bit.

Ai fini dell'apprendimento, dovresti probabilmente provare a seguire esattamente il tutorial, piuttosto che tradurre al volo a 64 bit:ci sono alcune altre significative differenze comportamentali in cui potresti imbatterti. Una volta che avrai familiarizzato con i386, allora puoi ritirare x86_64 separatamente.


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

e nota che usando int 0x80 per syscall su sistemi x64 è un vecchio livello di compatibilità. dovresti usare syscall istruzioni sui sistemi x64.

puoi ancora utilizzare questo vecchio metodo, ma devi compilare i tuoi binari in modalità x86, consulta il manuale del tuo compilatore/assembler per i dettagli.


la risposta di sunsetwuff indica correttamente che il meccanismo per le chiamate di sistema è diverso per Linux x86 a 64 bit rispetto a Linux a 32 bit.

Tuttavia, questa risposta è incompleta e fuorviante per un paio di motivi:

  • Il cambiamento è stato effettivamente introdotto prima che i sistemi a 64 bit diventassero popolari , motivato dall'osservazione che int 0x80 era molto lento su Pentium 4. Linus Torvalds ha codificato una soluzione usando SYSENTER /SYSEXIT istruzioni (che erano state introdotte da Intel intorno all'era Pentium Pro, ma che erano difettose e non davano alcun vantaggio pratico). Quindi i moderni sistemi Linux a 32 bit usano effettivamente SYSENTER , non int 0x80 .
  • I kernel Linux x86 a 64 bit in realtà non usano SYSENTER e SYSEXIT . In realtà usano il molto simile SYSCALL /SYSRET istruzioni.

Come sottolineato nei commenti, SYSENTER in realtà non funziona su molti sistemi Linux a 64 bit —vale a dire AMD a 64 bit sistemi.

È una situazione certamente confusa. I dettagli cruenti sono qui, ma il risultato è questo:

Per un kernel a 32 bit, SYSENTER/SYSEXIT sono l'unica coppia compatibile [tra CPU AMD e Intel]

Solo per un kernel a 64 bit in modalità Long... SYSCALL/SYSRET è l'unica coppia compatibile [tra CPU AMD e Intel]

Sembra che su un Intel CPU in modalità a 64 bit, puoi cavartela usando SYSENTER perché fa la stessa cosa di SYSCALL , tuttavia questo non è il caso dei sistemi AMD.

Conclusione:usa sempre SYSCALL su Linux su sistemi x86 a 64 bit . È ciò che effettivamente specifica l'ABI x86-64. (Vedi questa fantastica risposta wiki per ulteriori dettagli.)


Linux
  1. Linux:perché gli utenti Linux non utilizzano una chiamata di sistema per ottenere l'ora corrente?

  2. Linux:metodi di chiamata di sistema nel nuovo kernel?

  3. Migliori pratiche di codifica per la programmazione di sistemi Linux in linguaggio C – Parte 1

  4. Come richiamare una chiamata di sistema tramite syscall o sysenter in assembly inline?

  5. Impossibile chiamare la funzione della libreria standard C su Linux a 64 bit dal codice assembly (yasm).

Requisiti di sistema di Kali Linux

Comando di spegnimento di Linux

Comando Fsck in Linux

Linux è un sistema operativo o un kernel?

Documentare il tempo di attività del sistema in Linux

Come verificare il sistema Linux è a 32 o 64 bit?