0

I've been writing a program in NASM for Linux. I'd like to be able to return to the normal code path out of a signal handler that I've established for SIGFPE. Stripped-down sample code is:

section .text

global _start
_start:                  ; --- Enter the program ---
   mov      ebx,8        ; Load the signal to handle (SIGFPE)
   mov      ecx,.handle  ; Load the handler address
   mov      eax,48       ; Load the syscall number for signal
   int      0x80         ; Establish the handler
   mov      ebx,0        ; Prepare a divisor for SIGFPE
   idiv     ebx          ; Divide edx:eax by 0
   mov      ebx,0        ; Set exit status 0 (shouldn't get here)
   jmp      .exit        ; Exit the program

.handle:                 ; --- Handle a divide exception ---
   mov      ebx,31       ; Set exit status 31 (instead of real handling)

.exit:                   ; --- Exit the program ---
   mov      eax,1        ; Load the syscall number for exit
   int      0x80         ; Exit back to the system

Magic numbers are for compactness of code here.

Before the idiv instruction, esp is 0xffffcc00. At entry to the signal handler, esp is 0xffffc52c. Quite a bit of stuff has been put on the stack! There's a welter of information out there about __NR_sigreturn. I've had no luck trying to use it. A ret instruction in the handler just puts me back at the idiv instruction, this time with no handler.

Any ideas about what I can do at the .handle label to get back safely into the mainline?

(I know that sigaction is available, but I'd like to understand what's going on in this situation.)

Tony
  • 1,221
  • 2
  • 12
  • 25
  • When a signal is raised the kernel pushes context structures among other things onto the stack with all the information (registers, flags, eip etc) that need to be restored when the signal handler returns. – Michael Petch Sep 03 '15 at 18:24
  • 2
    When you do a `ret` you don't return directly back to the code that caused the signal to be raised. `ret` sends execution to something called the _signal trampoline_ . That code resides in the programs user space (not the kernel). Its job is to effectively call `sigreturn` which is responsible for restoring everything so that control returns back to a point where the signal was originally raised. Normally you don't call `sigreturn` directly. By using `sigaction` you alter the actions done by the signal processing code. – Michael Petch Sep 03 '15 at 18:44
  • Use setjmp/longjmp to return from the signal handler to a different location. – Ross Ridge Sep 03 '15 at 20:45

1 Answers1

1

A simple ret will return so as to reattempt the faulting instruction. When using sigaction to register the signal handler with the flag SA_SIGINFO, the third argument is a pointer to a ucontext_t that contains the saved state, which may be altered.

Timothy Baldwin
  • 3,551
  • 1
  • 14
  • 23