2010-04-24 5 views
11

Ich habe den folgenden Code, der eine Datei öffnet, liest es in einen Puffer und schließt dann die Datei.x86 Assembly: Bevor Sie einen Systemaufruf unter Linux durchführen, sollten Sie alle Register speichern?

Der Close-Dateisystemaufruf erfordert, dass die Dateibeschreibung im ebx-Register steht. Das ebx-Register erhält die Datei-Deskriptor-Nummer vor dem Lesen des Systemaufrufs. Meine Frage ist, sollte ich das ebx-Register auf dem Stapel oder irgendwo speichern, bevor ich den Systemaufruf lese, (könnte 80h das ebx-Register löschen?). Und dann das ebx-Register für das Schließen des Systemaufrufs wiederherstellen? Oder ist der Code, den ich unten habe, gut und sicher?

Ich habe den untenstehenden Code ausgeführt und es funktioniert, ich bin nur nicht sicher, ob es allgemein als gute Montagepraxis gilt oder nicht, weil ich das ebx-Register nicht vor dem Int 80h Leseanruf speichere.

;; 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

Vorschlag: Testen Sie, ob das Ergebnis des Lesens '<= 0 'auf dem schnellen Pfad ist, und sortieren Sie es dann in' Error' aus. Dies reduziert die Anzahl der Verzweigungsvorhersageeinträge, die Ihr Code normalerweise benötigt. 'jle' wird funktionieren, weil' test eax, eax' die Überlauf- und Carry-Flags löscht und SF und ZF entsprechend dem Ergebnis auf die gleiche Weise setzt wie 'cmp eax, 0'. –

Antwort

11

Den int 80h Anruf nicht selbst korrupt nichts wird, abgesehen von dem Rückgabewert in eax setzen. Also das Code-Fragment, das Sie haben, ist in Ordnung. (Wenn Ihr Codefragment jedoch Teil einer größeren Routine ist, von der erwartet wird, dass sie mit einem anderen Code nach dem üblichen Linux x86 ABI aufgerufen wird, müssen Sie ebx10 und möglicherweise andere Register bei der Eingabe Ihrer Routine beibehalten und beim Beenden wiederherstellen .)

Der entsprechende Code im Kernel kann in arch/x86/kernel/entry_32.S gefunden werden. Es ist ein bisschen schwer zu folgen, aufgrund der umfangreichen Verwendung von Makros und verschiedene Details (Unterstützung für Syscall-Tracing, DWARF-Debugging-Annotationen, etc.) aber: int 80h Handler ist system_call (Zeile 493 in der Version, die ich verknüpft habe); die Register werden über das Makro SAVE_ALL (Zeile 497) gespeichert; und sie werden wieder über RESTORE_REGS (Zeile 534) kurz vor der Rückkehr wiederhergestellt.

+0

Im Allgemeinen, nach 'syscall (2)', "können einige Architekturen unterschiedslos andere Register blockieren, die hier nicht aufgeführt sind". Genauer gesagt, x86-64 Systemaufrufe (mit 'syscall' gemacht) * tun * clobber' rcx' und 'r11', entsprechend meiner Lektüre von [this writeup of entry_64.S] (https://github.com/0xAX/ linux-inside/blob/master/SysCall/syscall-2.md). Dies wird durch die Tatsache unterstützt, dass der "sysret" -Befehl (verwendet von entry_64.S) "RIP = RCX" und "RFLAGS = R11", und einige Segment-Sachen. Sie sind nach der Ausführung wieder im Benutzermodus. ** AFAICT, x86-64 Syscalls behalten alles außer R11, RCX und RAX **. –

+0

Ich konnte keine spezifische Dokumentation oder sogar Kommentare im Code finden, die die genaue Situation für amd64 oder i386 angeben. Ich denke, es ist komisch, dass ein wichtiger Punkt für den Leser nur übrig bleibt, um die Makros zu entschlüsseln. Ich meine, in der Praxis sind es meistens nur libc-Implementoren, die diese Informationen benötigen, aber angesichts der Verpflichtung von Linux, einen stabilen ABI aufrechtzuerhalten, erwarte ich nicht, dass sich jemals etwas ändert. Also könnte es aufgeschrieben werden. (Und ich denke, hier, also habe ich upvoted: P) –

+0

Update ja, 'syscall' selbst Clobbers RCX/R11, und [Linux Systemaufrufe mit' syscall' nur Clobber diese + 'rax'] (https: // stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-on-i386-and-x86-6). Aber IIRC, es war meine Bearbeitung, die das beinhaltete; Ich kann mich nicht erinnern, ob ich jemals eine andere externe Dokumentation als den Quellcode von Linux gefunden habe. –

Verwandte Themen