Bonjour à tous.
Je ne peux que relancer mon sujet en essayant d'être plus clair.
(i) je cherche à récupérer depuis l'assembleur le signal SIGFPE, qui
correspond aux erreurs numériques déclenchées par le coprocesseur
mathématique, mais aussi par le processeur (instruction div ou idiv).
(ii) en défrichant à l'aide de C (et de gcc -S), j'ai vu un comportement
très spécial du préprocesseur de gcc:
les symboles d'indices pour indexer le type tableau greg_t (défini
dans sys/ucontext.h) ne sont pas visibles.
Pour le premier point, j'ai progressé en assembleur. Le nombre de
Memory access violation que j'ai récupéré depuis des programmes
écrits tant en C (en contournant le point (ii)) qu'en assembleur m'a
convaincu que le pointeur sur un ucontext_t passé à mon handler était
NULL ! D'où l'idée que j'étais directement dans le bon contexte. Du
coup, il suffit de remplacer le 'ret' en fin de handler par un 'pop'
suivi d'un 'jmp' pour obtenir le comportement que je souhaitais: traiter
l'erreur en un point de chute précis de mon programme.
Ce qui n'est faisable qu'en assembleur! C peut arriver à un résultat
proche avec setjmp / longjmp, mais pas tout à fait ce que je cherche.
Linux fonctionne donc pour sigaction très différemment de Solaris, au vu
de l'exemple trouvé sur Internet. Du coup, pas besoin du troisième
paramètre du handler, de type (de fait) *ucontext_t.
Toutefois il me reste un problème: une fois le handler utilisé, SIGFPE
retrouve son comportement par défaut.
Voici ce que j' obtiens avec mon programme envoyant en boucle à la
procédure effectuant le travail les valeurs 0, 1, 2 et 3, le dividende
étant 6:
SIGFPE récupéré
Valeur reçue sur eax: .
Valeur reçue sur eax: 0006.
Valeur reçue sur eax: 0003.
Valeur reçue sur eax: 0002.
La valeur est celle mise en place par le traitement d'erreur.
6, 3 et 2 sont les résultats de division par 1, 2 et 3, ensuite 0 est de
nouveau transmis, mais le message pour SIGFPE du système n'est même pas
dans le stderr du programme, je présume que c'est le shell qui me fait
le compte-rendu. Ce qui montre que le handler dans le programme a cessé
d'être pris en compte. J'ai fait plusieurs essais en réutilisant
sigaction, je n'ai pas jusque là trouvé de solution.
Pour si quelqu'un est curieux, je joins le programme assembleur. N.B.:
il est parfaitement autonome (à condition d'utiliser nasm). A propos, je
ne veux pas de polémique sur l'usage de int 80h, pour moi, quand je ne
travaille pas avec C, je n'utilise pas C, point. La portabilité n'est
pas un objectif quand on travaille en assembleur.
Pour le deuxième point, si j'ai (maladroitement semble-t-il) intitulé
mon message précédent usine à gaz des .h, c'est que je ne programme
pas seulement en assembleur, mais aussi en Ada. A chaque fois que je
veux appeler un service du système, c'est franchement la galère pour
l'interfacer, je souhaiterais que le préprocesseur soit capable de
fournir une meilleure documentation sur les données à utiliser (gcc -E
élimine en les interprétant les #define, or ce sont eux qui définissent
toutes les constantes). La programmation courante en C ne fait pas
apparaître le problème, seulement voilà, C est un langage que l'on peut
qualifier de bas niveau (citation tirée de Le langage C, Norme ANSI,
de Brian W. Kernighan et Denis M. Ritchie, deuxième édition, traduction
française Masson / Prentice Hall 1997, p. 2, justifiée très simplement
dans les lignes suivantes). Je ne l'utilise que pour des jeux d'essai ou
de petites fonctions servant d'interfaces.
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 30 juin 2014
;
; 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 ave cles valeurs sur
; ebx 0, 1, 2, 3 cycliquement (effect des deux instructions 'inc eax' et
; 'and eax, 3' (i.e. ___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!)
;
BITS 32
GLOBAL _start
SECTION .text
%idefine sys_exit 1
%idefine