2010-04-24 6 views
11

J'ai le code ci-dessous qui ouvre un fichier, le lit dans un tampon, puis ferme le fichier.x86 Assemblage: Avant de lancer un appel système sur Linux, devez-vous enregistrer tous les registres?

L'appel de fermeture de système de fichiers nécessite que le numéro de descripteur de fichier soit dans le registre ebx. Le registre ebx obtient le numéro de descripteur de fichier avant que l'appel système en lecture ne soit effectué. Ma question est que je devrais enregistrer le registre ebx sur la pile ou quelque part avant que je fasse l'appel système de lecture, (pourrait int 80h trash le registre ebx?). Et puis restaurer le registre ebx pour l'appel système proche? Ou le code que j'ai ci-dessous est-il bon et sûr?

J'ai exécuté le code ci-dessous et cela fonctionne, je ne suis pas sûr si cela est généralement considéré comme une bonne pratique d'assemblage ou non parce que je n'enregistre pas le registre ebx avant l'appel 80h int.

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

suggestion: Faire un test pour le résultat de la lecture étant '<= 0' sur le chemin rapide, puis le trier dans' Erreur'. Cela réduit la quantité d'entrées d'historique de prédiction de branchement dont votre code a normalement besoin. 'jle' fonctionnera, car' test eax, eax' efface le débordement et porte les drapeaux, et place SF et ZF selon le résultat de la même manière que 'cmp eax, 0'. –

Répondre

11

Le int 80h appel lui-même ne sera pas quelque chose de corruption, à part de mettre la valeur de retour dans eax. Donc, le fragment de code que vous avez est bien. (Mais si votre fragment de code fait partie d'une routine plus importante qui devrait être appelée par un autre code suivant l'ABI Linux x86 habituel, vous devrez conserver ebx, et éventuellement d'autres registres, à l'entrée de votre routine, et restaurer à la sortie

Le code correspondant dans le noyau peut être trouvé dans arch/x86/kernel/entry_32.S. C'est un peu difficile à suivre, en raison de l'utilisation étendue de macros et de divers détails (support pour le traçage syscall, annotations de débogage DWARF, etc.) mais: le gestionnaire int 80h est system_call (ligne 493 dans la version à laquelle j'ai lié); les registres sont enregistrés via la macro SAVE_ALL (ligne 497); et ils sont restaurés à nouveau via RESTORE_REGS (ligne 534) juste avant de revenir.

+0

En général, d'après 'syscall (2)', "certaines architectures peuvent indiscriminer d'autres registres non listés ici". Plus précisément, les appels système x86-64 (fait avec 'syscall') * font * clobber' rcx' et 'r11', selon ma lecture de [cet writeup of entry_64.S] (https://github.com/0xAX/ linux-insides/blob/maître/SysCall/syscall-2.md). Ceci est corroboré par le fait que l'instruction 'sysret' (utilisée par entry_64.S) fait' RIP = RCX', et 'RFLAGS = R11', et quelques trucs de segment. Vous êtes de retour en mode utilisateur après l'avoir exécuté. ** AFAICT, les syscalls x86-64 conservent tout sauf R11, RCX et RAX **. –

+0

Je n'ai pas pu trouver de documentation spécifique, ni même de commentaires dans le code, indiquant la situation exacte pour amd64 ou i386. Je pense qu'il est étrange qu'un point important comme celui-ci soit laissé aux lecteurs pour qu'ils décodent les macros. Je veux dire dans la pratique, ce sont surtout des implémenteurs de libc qui ont besoin de cette information, mais étant donné l'engagement de Linux à maintenir un ABI stable, je ne m'attends pas à ce que ça change. Donc, il pourrait être écrit. (Et j'ai deviné, ici, donc j'ai upvoted: P) –

+0

Mise à jour oui, 'syscall' lui-même clobbers RCX/R11, et [les appels système Linux faits en utilisant' syscall' seulement clobber ceux + 'rax'] (https: // stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-on-i386-and-x86-6). Mais IIRC, c'était mon montage qui incluait cela; Je ne me souviens pas si j'ai déjà trouvé de la documentation externe autre que le code source de Linux pour cela. –

Questions connexes