get_sigframe()通过用户态空间堆栈的sp-sizeof(struct sigframe)在用户态堆栈的顶部分配了一篇存储空间,将来使用完成后,再通过sp+sizeof(struct sigframe)还原。
通过上面的讨论,我们再回到do_signal()中来,如果有用户态的信号处理函数,do_signal()会调用handle_signal(),handle_signal()将调用setup_frame()或者setup_rt_frame()来完成实际的工作,这里我们以setup_frame()为例进行进一步讨论。
static int setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) { //在用户态堆栈上分配一个sigframe结构 struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame)); int err = 0;
if (!frame) return 1;
//把相关信息从内核态备份到用户态堆栈的sigframe结构中 err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]);
if (_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); }
if (err == 0) err = setup_return(regs, ka, &frame->retcode, frame, usig);
return err; } |
setup_return()设置返回地址,其定义如下:
static int setup_return(struct pt_regs *regs, struct k_sigaction *ka, unsigned long __user *rc, void __user *frame, int usig) { unsigned long handler = (unsigned long)ka->sa.sa_handler; unsigned long retcode; int thumb = 0; unsigned long cpsr = regs->ARM_cpsr & ~PSR_f;
/* * Maybe we need to deliver a 32-bit signal to a 26-bit task. */ if (ka->sa.sa_flags & SA_THIRTYTWO) cpsr = (cpsr & ~MODE_MASK) | USR_MODE;
#ifdef CONFIG_ARM_THUMB if (elf_hwcap & HWCAP_THUMB) { /* * The LSB of the handler determines if we're going to * be using THUMB or ARM mode for this signal handler. */ thumb = handler & 1;
if (thumb) cpsr |= PSR_T_BIT; else cpsr &= ~PSR_T_BIT; } #endif <SPAN style="WHITE-SPACE: pre"> </SPAN>//这里的retcode就是保存手工构造的sigreturn()代码 if (ka->sa.sa_flags & SA_RESTORER) { retcode = (unsigned long)ka->sa.sa_restorer; } else { unsigned int idx = thumb;
if (ka->sa.sa_flags & SA_SIGINFO) idx += 2;
if (__put_user(sigreturn_codes[idx], rc)) return 1;
if (cpsr & MODE32_BIT) { /* * 32-bit code can use the new high-page * signal return code support. */ retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb; } else { /* * Ensure that the instruction cache sees * the return code written onto the stack. */ flush_icache_range((unsigned long)rc, (unsigned long)(rc + 1));
retcode = ((unsigned long)rc) + thumb; } }
regs->ARM_r0 = usig; regs->ARM_sp = (unsigned long)frame;//堆栈 regs->ARM_lr = retcode;//返回地址,当用户态信号处理函数结束时,就会把这个地址作为返回地址 regs->ARM_pc = handler;//信号处理函数 regs->ARM_cpsr = cpsr;
return 0; } |
当setup_frame()返回后,一切准备就绪,因此可以从内核态返回了,这样就顺利过渡到用户态的信号处理函数。当这个函数处理结束后,会通过retcode再次进入内核态,现在我们看看retcode是如何处理的,下面的代码选自glibc(2.3.2):
#include <sysdep.h>
/* If no SA_RESTORER function was specified by the application we use one of these. This avoids the need for the kernel to synthesise a return instruction on the stack, which would involve expensive cache flushes. */
ENTRY(__default_sa_restorer) swi SYS_ify(sigreturn)
#ifdef __NR_rt_sigreturn
ENTRY(__default_rt_sa_restorer) swi SYS_ify(rt_sigreturn)
#define SYS_ify(syscall_name) (__NR_##syscall_name) |