Bonjour à tous

Je n'ai guère trouvé plus de documentation, mais "man sigreturn" m'a donné de nouvelles idées.

Le plus clair est dans le fichier joint (qui commence par 200 lignes de commentaires... c'est normal en assembleur), il me reste une question: quand je travaille en pur assembleur (fichier joint), le deuxième pointeur (*siginfo_t) passé au "handler" est NULL, alors que dès que je mélange C et assembleur, il pointe vers des données utilisables. Si quelqu'un est assez curieux pour m'aider, voir le fichier joint.

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.2
; Créé le 28 juin 2014
; Mis à jour le 2 juillet 2014, nettoyage des scories de la version C trouvée
;       sur Internet
; Deuxième mise à jour (1.1) avec essai tiré d'une variante (tpe_sinf.asm). 
; Mis à jour le 7 juillet 2014, finalisation de la correction en pile et
;       concentration de la documentation dans le source présent
;
;
;
; Auteur: Philippe Deleval
;
; Description:
;  version assembleur du programme de récupération de SIGFPE
;
;   Résultat des courses: le noyau enchaîne sur le handler de l'utilisateur
; dans le contexte général (même pile) du code comprenant le point où
; 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. Mais le handler utilsateur fait retour
; vers les "arcanes" de Linux (faire "man sigreturn" pour voir).
;
;   Cette version finale marche en "corrigeant" la pile! L'adresse de retour
; (marquée par 'blob' dans le texte ci-dessous) est remplacée par l'adresse
; 'corerr' et, au retour de l'interruption et du signal, la main est donnée
; au correcteur d'erreur associée à la fonction 'wrk', comme je le souhaitais.
;
;   Deux autres variantes marchent avec cette idée de changer en plongeant dans
; la pile pour changer la valeur de retour empilée lors du déclenchement de
; l'interuption:
;   fpe_asm.asm, le texte présent, est entièrement en assembleur, autonome.
;   fpe_fctasm.c est écrit en C, mais interface un handler et appelle une
; fonction 'wrk' en assembleur (fichier fpe_mixte.asm).
;   A l'inverse, fpe_ca.asm est en assembleur, mais sigaction est appelé via
; une fonction écrite en C (fichier sethand.c).
;
;   L'offset dans la pile change pace que C fait je ne sais quelle magouille
; avec son type siginfo_t. Le pointeur "si" dans le programme ici contenu est
; NULL quand signal_handler est appelé (interface ci-dessous).
;     void signal_handler (int signo, siginfo_t *si, void *data)
; Dans les deux autres programmes, il n'est pas nul et le contenu pointé est
; dans la pile, pas loin de son "sommet". D'où les corrections fonctionnant:
;   Ici, dans fpe_asm : 'mov dword [ebp+68], corerr'
;   Dans fpe_mixte    : 'mov dword [ebp+0e0h], corerr'
;   Dans fpe_ca       : 'mov dword [ebp + 224], corerr'
;
;   En fait, la correction est la même dans les deux derniers cas. En effet,
; 0e0h=14*16=224.
;
;   Il semble donc que quelque chose dans gcc/Linux fait occuper 156 octets de
; plus dans la pile au gestionnaire de signal émis par le noyau sur int 5. Ce
; n'est pas l'objet de type siginfo_t qui est de taille __SI_MAX_SIZE=128 (voir
; dans la documentation ci-dessous). Il reste 28 autres octets à expliquer.
;
;
; 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!)
;
;
;
;
; COMPLEMENTS 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);
;  };
;
;
;
; tiré de <bits/siginfo.h>
;# define __SI_MAX_SIZE     128
;# if __WORDSIZE == 64
;#  define __SI_PAD_SIZE     ((__SI_MAX_SIZE / sizeof (int)) - 4)
;# else
;#  define __SI_PAD_SIZE     ((__SI_MAX_SIZE / sizeof (int)) - 3)
;# endif
;
;typedef struct siginfo
;  {
;    int si_signo;              /* Signal number.  */
;    int si_errno;              /* If non-zero, an errno value associated with
;                                  this signal, as defined in <errno.h>.  */
;    int si_code;               /* Signal code.  */
;
;    union
;      {
;       int _pad[__SI_PAD_SIZE];
;
;        /* kill().  */
;       struct
;         {
;           __pid_t si_pid;     /* Sending process ID.  */
;           __uid_t si_uid;     /* Real user ID of sending process.  */
;         } _kill;
;
;       /* POSIX.1b timers.  */
;       struct
;         {
;           int si_tid;         /* Timer ID.  */
;           int si_overrun;     /* Overrun count.  */
;           sigval_t si_sigval; /* Signal value.  */
;         } _timer;
;
;       /* POSIX.1b signals.  */
;       struct
;         {
;           __pid_t si_pid;     /* Sending process ID.  */
;           __uid_t si_uid;     /* Real user ID of sending process.  */
;           sigval_t si_sigval; /* Signal value.  */
;         } _rt;
;
;       /* SIGCHLD.  */
;       struct
;         {
;           __pid_t si_pid;     /* Which child.  */
;           __uid_t si_uid;     /* Real user ID of sending process.  */
;           int si_status;      /* Exit value or signal.  */
;           __clock_t si_utime;
;           __clock_t si_stime;
;         } _sigchld;
;
;       /* SIGILL, SIGFPE, SIGSEGV, SIGBUS.  */
;       struct
;         {
;           void *si_addr;      /* Faulting insn/memory ref.  */
;         } _sigfault;
;
;       /* SIGPOLL.  */
;       struct
;         {
;           long int si_band;   /* Band event for SIGPOLL.  */
;           int si_fd;
;         } _sigpoll;
;      } _sifields;
;  } siginfo_t;
;
;....
;/* Values for `si_code'.  Positive values are reserved for kernel-generated
;   signals.  */
;....
;/* `si_code' values for SIGFPE signal.  */
;enum
;{
;  FPE_INTDIV = 1,              /* Integer divide by zero.  */
;# define FPE_INTDIV    FPE_INTDIV
;  FPE_INTOVF,                  /* Integer overflow.  */
;# define FPE_INTOVF    FPE_INTOVF
;  FPE_FLTDIV,                  /* Floating point divide by zero.  */
;# define FPE_FLTDIV    FPE_FLTDIV
;  FPE_FLTOVF,                  /* Floating point overflow.  */
;# define FPE_FLTOVF    FPE_FLTOVF
;  FPE_FLTUND,                  /* Floating point underflow.  */
;# define FPE_FLTUND    FPE_FLTUND
;  FPE_FLTRES,                  /* Floating point inexact result.  */
;# define FPE_FLTRES    FPE_FLTRES
;  FPE_FLTINV,                  /* Floating point invalid operation.  */
;# define FPE_FLTINV    FPE_FLTINV
;  FPE_FLTSUB                   /* Subscript out of range.  */
;# define FPE_FLTSUB    FPE_FLTSUB};
;
;
;

        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 edx, 1
        mov [var], edx
        mov ecx, 1024
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
        mov edx, bye.lg
        mov ecx, bye
        mov ebx, stdout
        mov eax, sys_write
        int 80h
        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
blob:   div ebx
        ; résultat sur eax
        leave
        ret
corerr: mov edx, thandl.lg
        mov ecx, thandl
        mov ebx, stdout
        mov eax, sys_write
        int 80h
        ;call vframe
        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 !
        ;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
        ; sortie du handler, redirection sur prototype de exception handler
        mov edx, txtfpe.lg ; deux premiers paramètres pour sys_write
        mov ecx, txtfpe
        mov ebx, stdout
        mov eax, sys_write
        int 80h
        ;mov esi, ebp
        ;mov ecx, 20
        ;.bctra:        mov eax, [esi]
        ;cmp eax, blob
        ;je .sbtra
        ;add esi, 4
        ;loop .bctra
        ;mov edx, tntr.lg
        ;mov ecx, tntr
        ;mov ebx, stderr
        ;mov eax, sys_write
        ;int 80h
        ;mov ebx, 0ffff_ffffh
        ;mov eax, sys_exit
        ;int 80h
        ;.sbtra:
        mov dword [ebp+68], corerr
        leave
        ret

;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é... "
.lg     equ $-txtfpe
tntr:   db "Retour non trouvé!", 10
.lg     equ $ - tntr
bye:    db "Tout s'est bien passé.", 10
.lg     equ $ - bye

        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
thandl: db "Passage par corerr, traite-exception de wrk", 10
.lg     equ $ - thandl
terrst: db "Code retour de sigaction: "
.nb:    times 8 db '0'
        db '.', 10
.lg     equ $ - terrst

        SECTION .bss
var:    resd 1
sa:     resb 144






Répondre à