2010-04-24 10 views
11

Ho il codice seguente che apre un file, lo legge in un buffer e quindi chiude il file.Assembly x86: prima di effettuare una chiamata di sistema su Linux, dovresti salvare tutti i registri?

La chiamata del file system chiusa richiede che il numero del descrittore di file sia nel registro ebx. Il registro ebx ottiene il numero del descrittore del file prima che venga effettuata la chiamata di sistema di lettura. La mia domanda è: dovrei salvare il registro di ebx nello stack o da qualche parte prima di effettuare la chiamata di sistema di lettura, (potrebbe int 80h trash il registro di ebx?). E poi ripristinare il registro ebx per la chiamata di sistema chiusa? O è il codice che ho sotto bene e sicuro?

Ho eseguito il codice seguente e funziona, non sono sicuro che sia generalmente considerato un buon esercizio di assemblaggio o meno perché non salvare il registro ebx prima della chiamata di lettura int 80h.

;; open up the input file 
mov eax,5  ; open file system call number 
mov ebx,[esp+8] ; null terminated string file name, first command line parameter 
mov ecx,0o  ; access type: O_RDONLY 
int 80h   ; file handle or negative error number put in eax 
test eax,eax 
js Error   ; test sign flag (SF) for negative number which signals error 

;; read in the full input file 
mov ebx,eax   ; assign input file descripter 
mov eax,3    ; read system call number 
mov ecx,InputBuff  ; buffer to read into 
mov edx,INPUT_BUFF_LEN ; total bytes to read 
int 80h 
test eax,eax 
js Error    ; if eax is negative then error 
jz Error    ; if no bytes were read then error 
add eax,InputBuff  ; add size of input to the begining of InputBuff location 
mov [InputEnd],eax  ; assign address of end of input 

;; close the input file 
;; file descripter is already in ebx 
mov eax,6  ; close file system call number 
int 80h   
+0

suggerimento: eseguire un test per il risultato della lettura come '<= 0' sul percorso veloce, quindi riordinarlo in' Errore'. Ciò riduce la quantità di voci della cronologia delle branch-branch normalmente necessarie per il codice. 'jle' funzionerà, perché' test eax, eax' cancella l'overflow e trasporta i flag, e imposta SF e ZF in base al risultato allo stesso modo 'cmp eax, 0'. –

risposta

11

Il int 80h chiamata in sé non danneggerà nulla, a parte mettere il valore di ritorno in eax. Quindi il frammento di codice che hai va bene. (Ma se il proprio frammento di codice fa parte di una routine più ampia che dovrebbe essere chiamata da un altro codice seguendo il solito ABI Linux x86, sarà necessario conservare ebx, e possibilmente altri registri, in entrata nella propria routine, e ripristinare all'uscita .)

Il codice pertinente nel kernel è disponibile in arch/x86/kernel/entry_32.S. È un po 'difficile da seguire, a causa dell'uso esteso di macro e di vari dettagli (supporto per traccia di syscall, annotazioni di debug di DWARF, ecc.) Ma: il gestore int 80h è system_call (riga 493 nella versione a cui sono collegato); i registri vengono salvati tramite la macro SAVE_ALL (riga 497); e vengono ripristinati nuovamente tramite RESTORE_REGS (riga 534) appena prima di tornare.

+0

In generale, in base a 'syscall (2)', "alcune architetture possono criptare indiscriminatamente altri registri non elencati qui". In particolare, chiamate di sistema x86-64 (fatte con 'syscall') * do * clobber' rcx' e 'r11', secondo la mia lettura di [questa scrittura di entry_64.S] (https://github.com/0xAX/ linux-interni/blob/master/sYSCALL/syscall-2.md). Ciò è supportato dal fatto che l'istruzione 'sysret' (usata da entry_64.S) fa' RIP = RCX', e 'RFLAGS = R11', e alcuni elementi del segmento. Sei tornato in modalità utente dopo averlo eseguito. ** AFAICT, x86-64 syscalls conserva tutto tranne R11, RCX e RAX **. –

+0

Impossibile trovare alcuna documentazione specifica o anche commenti nel codice, indicando la situazione esatta per amd64 o i386. Penso sia strano che un punto importante come questo sia lasciato ai lettori per risolvere il problema della decodifica dei macro. In pratica, in pratica sono principalmente implementatori di libc che necessitano di queste informazioni, ma dato l'impegno di Linux a mantenere un ABI stabile, non mi aspetto che cambierà mai. Quindi potrebbe essere scritto. (E ho indovinato, qui, così ho upvoted: P) –

+0

Aggiornamento sì, 'syscall' stesso clobbers RCX/R11, e [Le chiamate di sistema Linux fatte usando' syscall' solo clobber quelle + 'rax'] (https: // stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-on-i386-and-x86-6). Ma IIRC, era la mia modifica che includeva quello; Non ricordo se ho mai trovato documentazione esterna diversa dal codice sorgente di Linux per questo. –

Problemi correlati