2011-12-14 15 views
14

Attualmente sto imparando il linguaggio Assembly su Linux. Ho usato il libro 'Programming From the Ground Up' e tutti gli esempi sono a 32 bit. Il mio sistema operativo è 64-bit e ho cercato di fare tutti gli esempi in 64-bit. Tuttavia, sto riscontrando dei problemi:x86_64 Confusione chiamata sistema di assi Linux

.section .data 

.section .text 
.global _start 
_start: 
movq $60, %rax 
movq $2, %rbx 
int $0x80 

Questo semplicemente chiama la chiamata di sistema di uscita Linux o dovrebbe. Invece provoca un SEG FAULT e quando invece lo faccio,

.section .data 

.section .text 
.global _start 
_start: 
movq $1, %rax 
movq $2, %rbx 
int $0x80 

funziona. Chiaramente il problema è il valore che sposto in% rax. Il valore $ 1 che uso nel secondo esempio è 'Programming From the Ground Up', che dice di utilizzare comunque più fonti su Internet hanno affermato che il numero di sistema System a 64 bit è $ 60. Reference Cosa sto sbagliando? Anche quali altri problemi dovrei osservare e cosa dovrei usare per un riferimento? Nel caso avessi bisogno di sapere, sono al Capitolo 5 in Programmazione da zero.

risposta

15

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

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

Interrupt 0x80 invoca sempre chiamate di sistema a 32 bit. È 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 differenze comportamentali significative che potresti incontrare. Quando conosci i386, e poi puoi scegliere x86_64 separatamente.

+0

Probabilmente finirò per farlo. Grazie per la vostra risposta. –

+0

Si dovrebbe usare '% rdi' per il primo argomento di chiamata di sistema, non'% rbx'. –

+0

Grazie per averlo capito - risolto. – duskwuff

10

prega di leggere questo What are the calling conventions for UNIX & Linux system calls on x86-64

e si noti che l'uso di int 0x80 per chiamata di sistema sui sistemi x64 è un vecchio livello di compatibilità. dovresti usare le istruzioni syscall su sistemi x64.

è ancora possibile utilizzare questo vecchio metodo, ma è necessario compilare i file binari in modalità x86, consultare il manuale del compilatore/assemblatore per i dettagli.

+0

Felice di vedere qualcuno che fa notare che x86_64 Linux usa effettivamente 'syscall' not' sysenter'! Ho scritto una [risposta più lunga per spiegare la confusione tra i due] (// stackoverflow.com/a/31510342/20789). –

4

Molto è cambiato molto tra i386 e x86_64 incluse sia le istruzioni utilizzate per andare nel kernel che i registri usati per trasportare gli argomenti delle chiamate di sistema. Ecco il codice equivalente a quello acquistato:

.section .data 

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

Citando this answer a una domanda correlata:

La syscall numeri sono nel codice sorgente di Linux sotto 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 è invocata con l'istruzione "syscall". Syscall sovrascrive il registro rcx. Il ritorno è in corso.

+0

Sto anche facendo le cose nel manuale di shellcoder 2. Tuttavia, il mio sistema operativo è anche a 64 bit. Assemblo con nasm-option -f elf32 e i link anche con -melf_i386.Io uso gdb e anche evans debugger (comunque, sbagliato è compilato per 64 e richiede dopo aver caricato un binario, ma dentro edb, dentro gdb e in esecuzione, l'errore è lo stesso): segfault dopo un'istruzione DOPO int 0x80.E Voglio solo ESCI. Ho visto, il registro (r) ax deve contenere 0x3c invece di 0x01 (perché viene utilizzato il file syscall per 64 bit), ma non riesco a immaginare perché viene chiamata l'istruzione dopo int 0x80. , perché ? – icbytes

2

Se si controlla /usr/include/asm/unistd_32.h uscita corrisponde a 1 ma in /usr/include/asm/unistd_64.h uscita corrisponde a 60.

4

duskwuff 's answer indica correttamente 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 ragioni:

Come pointed out in the comments, SYSENTERin realtà non funziona su molti sistemi Linux a 64-bit -cioè a 64 bit di AMD sistemi.

È una situazione confusamente confusa. Il gory details are here, ma che cosa si tratta di è questo:

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

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

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

Riga inferiore: utilizzare sempre SYSCALL su Linux su sistemi x86 a 64 bit. È ciò che l'ABI x86-64 in realtà specifica. (Vedi questo ottimo wiki answer per ulteriori dettagli.)