[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: [HS] course vers SIGFPE



Bonjour à tous

Petit délai dans ma réponse, J'ai encore fait pas mal de recherches sur Internet, 'SIGFPE sigaction' donne beaucoup de résultats sur google, dont près de la moitié sont des exemplaires ou des copies de la page de manuel de sigaction! Il faut vraiment pas grand chose pour faire un cours...


Le 01/07/2014 17:09, Sylvain L. Sauvage a écrit :
(...)

Je vois deux possibilités :
1. (peu probable) tu as collé un SA_RESETHAND dans un coin ;

J'ai fait beaucoup d'essais, avec ou sans le "drapeau" SA_RESETHAND, sans variation de comportement.

2. ce que tu fais dans le gestionnaire de signal empêche le
   réarmement automatique du signal.

J'ai fait un essai minimal où le handler ne fait que détourner le 'ret' vers l'instruction de mon choix (deux instructions: pop eax et jmp afferr !) Même comportement. Mon "programme principal" passe en boucle à la routine de travail 0, 1, 2, 3, 0, 1, 2, 3. la première fois qu'elle passe 0, mon handler fonctionne, la deuxième fois, processus terminé par SIGFPE!

Je joins mon texte en assembleur (nasm), avec tous les commentaires qui en font une historique.

N.B.: ce n'est pas une affaire de coprocesseur ! C'est le processeur lui-même qui déclenche l'interruption 5 quand un problème se pose avec 'div' ou 'idiv'. Comme le coprocesseur déclenche la même interruption en cas de problème si ses flags ont été configurés pour, la réaction du noyau Linux est la même: SIGFPE.

Si vraiment je suis trop hors sujet, à qui, quelle liste dois-je m'adresser? j'ai fait un tour dans la liste (!) des listes Debian, aucune n'est prévue pour ce genre de problème. Où dois-je signaler un bug dans sigaction?

Cordialement

Philippe Deleval

; chapeau pour programmes ou modules écrits en assembleur
; inspiré du "header" suggéré par Jeff Duntemann ("Assembly Language Step
; by Step", troisième édition, Wiley 2009)
;
; fichier source: fpe_asm.asm
; fichier produit: fpe_asm
;
; version 1.0
; Créé le 28 juin 2014
; Mis à jour le 2 juillet 2014, nettoyage des scories de la version C trouvée
;	sur Internet
;
; Auteur: Philippe Deleval
;
; Description:
;  version assembleur du programme de récupération de SIGFPE
;  version avec détournement du 'ret' du handler
;  Résultat des courses: le noyau enchaîne sur le handler de l'utilisateur
;  avec le contexte qu'il aurait s'il était appelé par 'call' depuis le point
;  ou le hardware a lancé 'int 5' (réaction aux erreurs de "Floating Point",
;  mais aussi aux divisions par zéro ou débordements de 'div' ou 'idiv'), ce
;  que le noyau convertit en SIGFPE.
;  Si ça marche sur la première captation de SIGFPE, je ne trouve pas le moyen
;  de relancer et réinstaller le 'handler' après usage!
;
; N.B.: le programme principal appelle la procédure "wrk" avec les valeurs sur
; ebx 0, 1, 2, 3 cycliquement (effect des deux instructions 'inc eax' et
; 'and eax, 3' (i.e. 0000_0000_0000_0111 binaire).
; 
; 
; Commande d'assemblage: nasm -f elf fpe_asm.asm
; Commande d'édition de liens: ld -s -x -o fpe_asm fpe_asm.o (sauf si debug!)
;
;
; Compléments de documentation:
;
; tiré de <bits/sigset.h>:
;/* A `sigset_t' has a bit for each signal.  */
;
;# define _SIGSET_NWORDS	(1024 / (8 * sizeof (unsigned long int)))
;typedef struct
;  {
;    unsigned long int __val[_SIGSET_NWORDS];
;  } __sigset_t;
;
; tiré de <bits/sigaction.h> et simplifié en assumant __USE_POSIX199309 !
; 
;/* Structure describing the action to be taken when a signal arrives.  */
;struct sigaction
;  {
;    /* Signal handler.  */
;    union
;      {
;	/* Used if SA_SIGINFO is not set.  */
;	__sighandler_t sa_handler;
;	/* Used if SA_SIGINFO is set.  */
;	void (*sa_sigaction) (int, siginfo_t *, void *);
;      }
;    __sigaction_handler;
;
;    /* Additional set of signals to be blocked.  */
;    __sigset_t sa_mask;
;
;    /* Special flags.  */
;    int sa_flags;
;
;    /* Restore handler.  */
;    void (*sa_restorer) (void);
;  };

	BITS 32
	GLOBAL _start

	SECTION .text

%idefine sys_exit	1
%idefine sys_read	3
%idefine sys_write	4
%idefine sys_sigaction	67
%idefine stdin		0
%idefine stdout		1
%idefine stderr		2

%define SIGFPE	8 ; code de SIGFPE d'après fpe_v0.s

; valeurs tirées de <bits/sigaction.h> 
; Bits in `sa_flags'.
%define	SA_NOCLDSTOP  1		; Don't send SIGCHLD when children stop.
%define SA_NOCLDWAIT  2		; Don't create zombie on child death.
%define SA_SIGINFO    4		; Invoke signal-catching function with
				;   three arguments instead of one.
%define SA_ONSTACK   0x08000000 ; Use signal stack by using `sa_restorer'.
%define SA_RESTART   0x10000000 ; Restart syscall on signal return.
%define SA_NODEFER   0x40000000 ; Don't automatically block the signal when
				;   its handler is being executed.
%define SA_RESETHAND 0x80000000 ; Reset to SIG_DFL on entry to handler.
%define SA_INTERRUPT 0x20000000 ; Historical no-op.

_start:	; programme fpe_asm
	; nettoyage de (sigaction) [sa]
	cld
	mov edi, sa
	mov ecx, 35 ; 4 * 35 = 140
	xor eax, eax
	rep stosd
	;mov dword [sa+4], 0ffff_ffffh ; [sa+4] = sa.sa_mask[0]
	;sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
	;sa.sa_flags = [sa+132]
	;[sa+132] car [sa] adresse ou entier (4 octets), et [sa+4] tableau de
	; 1024 / (8 * 4) = 32 'long integer' (qui sont 32 bits sur système
	;32 bits), donc 128 octets (type __sigset_t donné ci-dessus, sous le
	;chapeau).
	;mov dword [sa+132], 402653188 ; tiré de fpe_v0.s
	mov dword [sa+132], SA_SIGINFO
	;
	;sa.sa_sigaction = signal_handler;
	mov dword [sa], signal_handler ; tiré de fpe_v0.s
	; sigaction(SIGFPE, &sa, &osa);
	xor edx, edx ; NULL comme troisième paramètre &osa
	mov ecx, sa
	mov ebx, SIGFPE
	mov eax, sys_sigaction
	int 80h
	test eax, eax
	jnz errst
	xor edx, edx
	mov [var], edx
	mov ecx, 12
bcpr:	push ecx
	mov eax, [var]
	mov ebx, eax
	inc eax
	and eax, 3
	mov [var], eax
	call wrk
	mov edi, txtret.nb
	call nbtohex
	mov edx, txtret.lg
	mov ecx, txtret
	mov ebx, stdout
	mov eax, sys_write
	int 80h
	pop ecx
.tstb:	loop bcpr
	xor ebx, ebx
	mov eax, sys_exit
	int 80h
errst:	; erreur dans sigaction
	mov edi, terrst.nb
	call nbtohex
	mov edx, terrst.lg
	mov ecx, terrst
	mov ebx, stderr
	mov eax, sys_write
	int 80h
	xor ebx, ebx
	dec ebx
	mov eax, sys_exit
	int 80h

wrk:	; prend ebx en paramètre
	; renvoie 1 ! mais si ebx=0, traitement d'erreur
	push ebp
	mov ebp, esp
	;
	;  b /= 0x0;
	;
	;  return b;
	;}
	;call vframe ; vframe sauvegarde ebx
	mov eax, 6
	xor edx, edx
	div ebx
	; résultat sur eax
	leave
	ret
afferr:	mov edx, txtfpe.lg ; deux premiers paramètres pour sys_write
	mov ecx, txtfpe
	mov ebx, stderr
	mov eax, sys_write
	int 80h
	mov eax, 0ffff_ffffh
	leave
	ret

	;void signal_handler (int signo, siginfo_t *si, void *data) {
signal_handler:	;push ebp
	;mov ebp, esp
	;  /* ucontext_t *uc;
	;     uc = (ucontext_t *) data; */
	;; uc sur [ebp+16]
	; fprintf(stdout, "Caught FPE\n");
	; reporté en fonction appeleuse.
	;    /*>uc->uc_mcontext.gregs[REG_PC]=uc->uc_mcontext.gregs[REG_nPC];*/
	; corrigé en uc->uc_mcontext.gregs[REG_EBX]=1;
	;mov edi, [ebp+16] ;troisième paramètre (ucontext_t *)
	;test edi, edi ;[ebp+16] semble bien null = 0 !
	;je leve
	;mov ebp, [edi+(20+4 * REG_EBP)] ?
	;mov esp, [edi+(20+4 * REG_ESP)] ?
	;mov dword [edi+off_ebx], 1
	;mov dword [edi+off_edx], 1
	;mov dword [edi+off_ecx], 1
	;mov dword [edi+off_eax], 1
	;leave
	;ret
;leve:	; sortie du handler, redirection sur prototype de exception handler
	;xor edx, edx ; NULL comme troisième paramètre &osa
	;mov ecx, sa; laissé invariant par appel de sigaction d'après prototype
	;mov ebx, SIGFPE
	;mov eax, sys_sigaction
	;int 80h
	;leave
	pop eax ; ret détourné
	;add esp, 12 ;nettoyage de pile --> 'leave' après afferr!
	jmp short afferr
	

;vframe:
;	;affichage du "contexte" (stack frame) de la procédure appelante
;	push ebp
;	mov ebp, esp
;	push ebx ; sauvegarde de ebx pour cause d'appel par wrk
;	mov eax, esp
;	add eax, 12 ; adresse retour plus empilage de ebp et place de ebx
;	mov byte [txtsf.info], 's'
;	mov edi, txtsf.nb
;	call nbtohex
;	mov edx, txtsf.lg
;	mov ecx, txtsf
;	mov ebx, stdout
;	mov eax, sys_write
;	int 80h
;	mov eax, [ebp] ; valeur empilée de ebp
;	mov byte [txtsf.info], 'b'
;	mov edi, txtsf.nb
;	call nbtohex
;	mov edx, txtsf.lg
;	mov ecx, txtsf
;	mov ebx, stdout
;	mov eax, sys_write
;	int 80h
;	pop ebx
;	leave
;	ret
;
nbtohex:
	; attend en paramètre sur eax un nombre (32 bits non signé)
	;et l'adresse d'un buffer sur edi
	;;  affiche en quatre chiffres hexadécimaux de [edi] à [edi+3]
	mov edx, eax ; nombre
	; edi pointeur buffer (destination de la conversion)
	mov ecx, 8 ; nombre de chiffres
	add edi, ecx ; déplace le pointeur au dernier chiffre demandé
	dec edi ; correction!
	std
.boucle	mov eax, edx ; extraction du chiffre
	and eax, 000FH
	shr edx, 4 ; division par 16
	cmp eax, 0ah ; traitement différent si chiffre entre 0 et 9 ou A et F
	jb .mdix
	add eax, 37H
	jmp short .ecrire
.mdix	add eax, 30H
.ecrire	stosb ; utilise et met à jour le pointeur
	loop .boucle ; sortie si compteur ecx épuisé
	ret


	SECTION .rodata
txtfpe:	db "SIGFPE récupéré", 10
.lg	equ $-txtfpe

	SECTION .data
txtret:	db "Valeur reçue sur eax: "
.nb:	times 8 db '0'
	db '.', 10
.lg	equ $ - txtret
;txtsf:	db "Contenu du registre e"
;.info:	db ' ', "p:"
;.nb:	times 8 db '0'
;	db '.', 10
;.lg	equ $ - txtsf
terrst:	db "Code retour de sigaction: "
.nb:	times 8 db '0'
	db '.', 10
.lg	equ $ - terrst
	SECTION .bss
var:	resd 1
sa:	resb 144







Reply to: