linux(4): Cleanup signal trampolines

This is the first stage of a signal trampolines refactoring.

From trampolines retired emulation of the 'call' instruction, which is
replaced by direct call of a signal handler. The signal handler address
is in the register.

The previous trampoline implemenatation used semi-Linux-way to call
a signal handler via the 'jmp' instruction. Wherefore the trampoline
emulated a 'call' instruction to into the stack the return address for
signal handler's 'ret' instruction.  Wherefore handmade DWARD annotations
was used.

While here rephrased and removed excessive comments.

MFC after:		2 weeks
This commit is contained in:
Dmitry Chagin 2022-05-15 21:00:05 +03:00
parent 0b5d5dc376
commit ba279bcd6d
12 changed files with 27 additions and 82 deletions

View file

@ -314,7 +314,6 @@ typedef struct l_siginfo {
struct l_rt_sigframe {
struct l_ucontext sf_sc;
struct l_siginfo sf_si;
l_handler_t sf_handler;
};
/*

View file

@ -8,7 +8,6 @@ __FBSDID("$FreeBSD$");
#include <amd64/linux/linux.h>
#include <compat/linux/linux_mib.h>
ASSYM(LINUX_RT_SIGF_HANDLER, offsetof(struct l_rt_sigframe, sf_handler));
ASSYM(LINUX_RT_SIGF_UC, offsetof(struct l_rt_sigframe, sf_sc));
ASSYM(LINUX_RT_SIGF_SC, offsetof(struct l_ucontext, uc_mcontext));
ASSYM(LINUX_VERSION_CODE, LINUX_VERSION_CODE);

View file

@ -11,23 +11,14 @@
linux_platform:
.asciz "x86_64"
.text
/*
* To avoid excess stack frame the signal trampoline code emulates
* the 'call' instruction.
*/
ENTRY(linux_rt_sigcode)
movq %rsp, %rbx /* preserve sigframe */
call .getip
.getip:
popq %rax
add $.startrtsigcode-.getip, %rax /* ret address */
pushq %rax
jmp *LINUX_RT_SIGF_HANDLER(%rbx)
movq %rsp, %rbx /* rt_sigframe for rt_sigreturn */
call *%rcx /* call signal handler */
.startrtsigcode:
movq $LINUX_SYS_linux_rt_sigreturn,%rax /* linux_rt_sigreturn() */
syscall /* enter kernel with args */
movq $LINUX_SYS_linux_rt_sigreturn, %rax
syscall
hlt
.endrtsigcode:
0: jmp 0b

View file

@ -686,10 +686,10 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
regs->tf_rax = 0;
regs->tf_rsi = (register_t)&sfp->sf_si; /* arg 2 in %rsi */
regs->tf_rdx = (register_t)&sfp->sf_sc; /* arg 3 in %rdx */
regs->tf_rcx = (register_t)catcher;
/* Fill in POSIX parts. */
siginfo_to_lsiginfo(&ksi->ksi_info, &sf.sf_si, sig);
sf.sf_handler = catcher;
mtx_unlock(&psp->ps_mtx);
PROC_UNLOCK(p);

View file

@ -429,15 +429,12 @@ struct l_fpstate {
/*
* We make the stack look like Linux expects it when calling a signal
* handler, but use the BSD way of calling the handler and sigreturn().
* This means that we need to pass the pointer to the handler too.
* It is appended to the frame to not interfere with the rest of it.
*/
struct l_sigframe {
l_int sf_sig;
struct l_sigcontext sf_sc;
struct l_fpstate sf_fpstate;
l_uint sf_extramask[1];
l_handler_t sf_handler;
};
struct l_rt_sigframe {
@ -446,7 +443,6 @@ struct l_rt_sigframe {
l_uintptr_t sf_ucontext;
l_siginfo_t sf_si;
struct l_ucontext sf_sc;
l_handler_t sf_handler;
} __packed;
/*

View file

@ -9,9 +9,7 @@ __FBSDID("$FreeBSD$");
#include <amd64/linux32/linux.h>
#include <compat/linux/linux_mib.h>
ASSYM(LINUX_SIGF_HANDLER, offsetof(struct l_sigframe, sf_handler));
ASSYM(LINUX_SIGF_SC, offsetof(struct l_sigframe, sf_sc));
ASSYM(LINUX_RT_SIGF_HANDLER, offsetof(struct l_rt_sigframe, sf_handler));
ASSYM(LINUX_RT_SIGF_UC, offsetof(struct l_rt_sigframe, sf_sc));
ASSYM(LINUX_RT_SIGF_SC, offsetof(struct l_ucontext, uc_mcontext));
ASSYM(LINUX_VERSION_CODE, LINUX_VERSION_CODE);

View file

@ -14,38 +14,22 @@ linux_platform:
.text
.code32
/*
* To avoid excess stack frame the signal trampoline code emulates
* the 'call' instruction.
*/
ENTRY(__kernel_sigreturn)
movl %esp, %ebx /* preserve sigframe */
call .getip0
.getip0:
popl %eax
add $.startsigcode-.getip0, %eax /* ret address */
push %eax
jmp *LINUX_SIGF_HANDLER(%ebx)
movl %esp, %ebx /* sigframe for sigreturn */
call *%edi /* call signal handler */
.startsigcode:
popl %eax
movl $LINUX32_SYS_linux_sigreturn,%eax /* linux_sigreturn() */
int $0x80 /* enter kernel with args */
popl %eax /* gcc unwind code need this */
movl $LINUX32_SYS_linux_sigreturn, %eax
int $0x80
.endsigcode:
0: jmp 0b
ENTRY(__kernel_rt_sigreturn)
leal LINUX_RT_SIGF_UC(%esp),%ebx /* linux ucp */
leal LINUX_RT_SIGF_SC(%ebx),%ecx /* linux sigcontext */
movl %esp, %edi
call .getip1
.getip1:
popl %eax
add $.startrtsigcode-.getip1, %eax /* ret address */
push %eax
jmp *LINUX_RT_SIGF_HANDLER(%edi)
leal LINUX_RT_SIGF_UC(%esp), %ebx /* linux ucontext for rt_sigreturn */
call *%edi /* call signal handler */
.startrtsigcode:
movl $LINUX32_SYS_linux_rt_sigreturn,%eax /* linux_rt_sigreturn() */
int $0x80 /* enter kernel with args */
movl $LINUX32_SYS_linux_rt_sigreturn, %eax
int $0x80
.endrtsigcode:
0: jmp 0b

View file

@ -314,7 +314,6 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
bzero(&frame, sizeof(frame));
frame.sf_handler = PTROUT(catcher);
frame.sf_sig = sig;
frame.sf_siginfo = PTROUT(&fp->sf_si);
frame.sf_ucontext = PTROUT(&fp->sf_sc);
@ -367,6 +366,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
/* Build context to run handler in. */
regs->tf_rsp = PTROUT(fp);
regs->tf_rip = __kernel_rt_sigreturn;
regs->tf_rdi = PTROUT(catcher);
regs->tf_rflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucode32sel;
regs->tf_ss = _udatasel;
@ -431,7 +431,6 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
bzero(&frame, sizeof(frame));
frame.sf_handler = PTROUT(catcher);
frame.sf_sig = sig;
bsd_to_linux_sigset(mask, &lmask);
@ -473,6 +472,7 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
/* Build context to run handler in. */
regs->tf_rsp = PTROUT(fp);
regs->tf_rip = __kernel_sigreturn;
regs->tf_rdi = PTROUT(catcher);
regs->tf_rflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucode32sel;
regs->tf_ss = _udatasel;

View file

@ -404,15 +404,12 @@ struct l_fpstate {
/*
* We make the stack look like Linux expects it when calling a signal
* handler, but use the BSD way of calling the handler and sigreturn().
* This means that we need to pass the pointer to the handler too.
* It is appended to the frame to not interfere with the rest of it.
*/
struct l_sigframe {
l_int sf_sig;
struct l_sigcontext sf_sc;
struct l_fpstate sf_fpstate;
l_uint sf_extramask[LINUX_NSIG_WORDS-1];
l_handler_t sf_handler;
};
struct l_rt_sigframe {
@ -421,7 +418,6 @@ struct l_rt_sigframe {
struct l_ucontext *sf_ucontext;
l_siginfo_t sf_si;
struct l_ucontext sf_sc;
l_handler_t sf_handler;
};
extern struct sysentvec linux_sysvec;

View file

@ -8,11 +8,9 @@ __FBSDID("$FreeBSD$");
#include <i386/linux/linux.h>
#include <compat/linux/linux_mib.h>
ASSYM(LINUX_SIGF_HANDLER, offsetof(struct l_sigframe, sf_handler));
ASSYM(LINUX_SIGF_SC, offsetof(struct l_sigframe, sf_sc));
ASSYM(LINUX_SC_GS, offsetof(struct l_sigcontext, sc_gs));
ASSYM(LINUX_SC_EFLAGS, offsetof(struct l_sigcontext, sc_eflags));
ASSYM(LINUX_RT_SIGF_HANDLER, offsetof(struct l_rt_sigframe, sf_handler));
ASSYM(LINUX_RT_SIGF_UC, offsetof(struct l_rt_sigframe, sf_sc));
ASSYM(LINUX_RT_SIGF_SC, offsetof(struct l_ucontext, uc_mcontext));
ASSYM(LINUX_SC_ESP, offsetof(struct l_sigcontext, sc_esp));

View file

@ -15,38 +15,22 @@ linux_platform:
.text
/*
* To avoid excess stack frame the signal trampoline code emulates
* the 'call' instruction.
*/
ENTRY(__kernel_sigreturn)
movl %esp, %ebx /* preserve sigframe */
call .getip0
.getip0:
popl %eax
add $.startsigcode-.getip0, %eax /* ret address */
push %eax
jmp *LINUX_SIGF_HANDLER(%ebx)
movl %esp, %ebx /* sigframe for sigreturn */
call *%edi /* call signal handler */
.startsigcode:
popl %eax /* gcc unwind code need this */
movl $LINUX_SYS_linux_sigreturn,%eax /* linux_sigreturn() */
int $0x80 /* enter kernel with args */
movl $LINUX_SYS_linux_sigreturn, %eax
int $0x80
.endsigcode:
0: jmp 0b
ENTRY(__kernel_rt_sigreturn)
leal LINUX_RT_SIGF_UC(%esp),%ebx /* linux ucp */
leal LINUX_RT_SIGF_SC(%ebx),%ecx /* linux sigcontext */
movl %esp, %edi
call .getip1
.getip1:
popl %eax
add $.startrtsigcode-.getip1, %eax /* ret address */
push %eax
jmp *LINUX_RT_SIGF_HANDLER(%edi)
leal LINUX_RT_SIGF_UC(%esp), %ebx /* linux ucontext for rt_sigreturn */
call *%edi /* call signal handler */
.startrtsigcode:
movl $LINUX_SYS_linux_rt_sigreturn,%eax /* linux_rt_sigreturn() */
int $0x80 /* enter kernel with args */
movl $LINUX_SYS_linux_rt_sigreturn, %eax
int $0x80
.endrtsigcode:
0: jmp 0b

View file

@ -422,7 +422,6 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
bzero(&frame, sizeof(frame));
frame.sf_handler = catcher;
frame.sf_sig = sig;
frame.sf_siginfo = &fp->sf_si;
frame.sf_ucontext = &fp->sf_sc;
@ -473,6 +472,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
/* Build context to run handler in. */
regs->tf_esp = (int)fp;
regs->tf_eip = __kernel_rt_sigreturn;
regs->tf_edi = catcher;
regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D);
regs->tf_cs = _ucodesel;
regs->tf_ds = _udatasel;
@ -532,7 +532,6 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
bzero(&frame, sizeof(frame));
frame.sf_handler = catcher;
frame.sf_sig = sig;
bsd_to_linux_sigset(mask, &lmask);
@ -574,6 +573,7 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
/* Build context to run handler in. */
regs->tf_esp = (int)fp;
regs->tf_eip = __kernel_sigreturn;
regs->tf_edi = catcher;
regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D);
regs->tf_cs = _ucodesel;
regs->tf_ds = _udatasel;