Implement vdso - virtual dynamic shared object. Through vdso Linux
exposes functions from kernel with proper DWARF CFI information so that it becomes easier to unwind through them. Using vdso is a mandatory for a thread cancelation && cleanup on a modern glibc. Differential Revision: https://reviews.freebsd.org/D1060
This commit is contained in:
parent
ec513841b3
commit
bdc379344a
@ -114,7 +114,7 @@ typedef struct {
|
||||
/*
|
||||
* Miscellaneous
|
||||
*/
|
||||
#define LINUX_AT_COUNT 16 /* Count of used aux entry types.
|
||||
#define LINUX_AT_COUNT 18 /* Count of used aux entry types.
|
||||
* Keep this synchronized with
|
||||
* elf_linux_fixup() code.
|
||||
*/
|
||||
|
@ -7,9 +7,12 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/systm.h>
|
||||
|
||||
#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);
|
||||
ASSYM(LINUX_SC_ESP, offsetof(struct l_sigcontext, sc_esp));
|
||||
|
@ -8,31 +8,143 @@
|
||||
.text
|
||||
.code32
|
||||
|
||||
NON_GPROF_ENTRY(linux_sigcode)
|
||||
call *LINUX_SIGF_HANDLER(%esp)
|
||||
leal LINUX_SIGF_SC(%esp),%ebx /* linux scp */
|
||||
movl %esp, %ebx /* pass sigframe */
|
||||
push %eax /* fake ret addr */
|
||||
/*
|
||||
* To avoid excess stack frame the signal trampoline code emulates
|
||||
* the 'call' instruction.
|
||||
*/
|
||||
NON_GPROF_ENTRY(linux32_sigcode)
|
||||
movl %esp, %ebx /* preserve sigframe */
|
||||
call .getip0
|
||||
.getip0:
|
||||
popl %eax
|
||||
add $.startsigcode-.getip0, %eax /* ret address */
|
||||
push %eax
|
||||
jmp *LINUX_SIGF_HANDLER(%ebx)
|
||||
.startsigcode:
|
||||
popl %eax
|
||||
movl $LINUX_SYS_linux_sigreturn,%eax /* linux_sigreturn() */
|
||||
int $0x80 /* enter kernel with args */
|
||||
.endsigcode:
|
||||
0: jmp 0b
|
||||
ALIGN_TEXT
|
||||
/* XXXXX */
|
||||
linux_rt_sigcode:
|
||||
call *LINUX_RT_SIGF_HANDLER(%esp)
|
||||
|
||||
NON_GPROF_ENTRY(linux32_rt_sigcode)
|
||||
leal LINUX_RT_SIGF_UC(%esp),%ebx /* linux ucp */
|
||||
leal LINUX_RT_SIGF_SC(%ebx),%ecx /* linux sigcontext */
|
||||
push %eax /* fake ret addr */
|
||||
movl %esp, %edi
|
||||
call .getip1
|
||||
.getip1:
|
||||
popl %eax
|
||||
add $.startrtsigcode-.getip1, %eax /* ret address */
|
||||
push %eax
|
||||
jmp *LINUX_RT_SIGF_HANDLER(%edi)
|
||||
.startrtsigcode:
|
||||
movl $LINUX_SYS_linux_rt_sigreturn,%eax /* linux_rt_sigreturn() */
|
||||
int $0x80 /* enter kernel with args */
|
||||
.endrtsigcode:
|
||||
0: jmp 0b
|
||||
ALIGN_TEXT
|
||||
/* XXXXX */
|
||||
linux_esigcode:
|
||||
|
||||
.data
|
||||
.globl linux_szsigcode, linux_sznonrtsigcode
|
||||
linux_szsigcode:
|
||||
.long linux_esigcode-linux_sigcode
|
||||
linux_sznonrtsigcode:
|
||||
.long linux_rt_sigcode-linux_sigcode
|
||||
NON_GPROF_ENTRY(linux32_vsyscall)
|
||||
.startvsyscall:
|
||||
int $0x80
|
||||
ret
|
||||
.endvsyscall:
|
||||
|
||||
|
||||
.section .note.Linux, "a",@note
|
||||
.long 2f - 1f /* namesz */
|
||||
.balign 4
|
||||
.long 4f - 3f /* descsz */
|
||||
.long 0
|
||||
1:
|
||||
.asciz "Linux"
|
||||
2:
|
||||
.balign 4
|
||||
3:
|
||||
.long LINUX_VERSION_CODE
|
||||
4:
|
||||
.balign 4
|
||||
.previous
|
||||
|
||||
|
||||
#define do_cfa_expr(offset) \
|
||||
.byte 0x0f; /* DW_CFA_def_cfa_expression */ \
|
||||
.uleb128 11f-10f; /* length */ \
|
||||
10: .byte 0x74; /* DW_OP_breg4 */ \
|
||||
.sleb128 offset; /* offset */ \
|
||||
.byte 0x06; /* DW_OP_deref */ \
|
||||
11:
|
||||
|
||||
|
||||
/* CIE */
|
||||
.section .eh_frame,"a",@progbits
|
||||
.LSTARTFRAMEDLSI1:
|
||||
.long .LENDCIEDLSI1-.LSTARTCIEDLSI1
|
||||
.LSTARTCIEDLSI1:
|
||||
.long 0 /* CIE ID */
|
||||
.byte 1 /* Version number */
|
||||
.string "zRS" /* NULL-terminated
|
||||
* augmentation string
|
||||
*/
|
||||
.uleb128 1 /* Code alignment factor */
|
||||
.sleb128 -4 /* Data alignment factor */
|
||||
.byte 8 /* Return address
|
||||
* register column
|
||||
*/
|
||||
.uleb128 1 /* Augmentation value length */
|
||||
.byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
|
||||
.byte 0 /* DW_CFA_nop */
|
||||
.align 4
|
||||
.LENDCIEDLSI1:
|
||||
|
||||
/* FDE */
|
||||
.long .LENDFDEDLSI1-.LSTARTFDEDLSI1 /* Length FDE */
|
||||
.LSTARTFDEDLSI1:
|
||||
.long .LSTARTFDEDLSI1-.LSTARTFRAMEDLSI1 /* CIE pointer */
|
||||
.long .startsigcode-. /* PC-relative start address */
|
||||
.long .endsigcode-.startsigcode
|
||||
.uleb128 0 /* Augmentation */
|
||||
do_cfa_expr(LINUX_SIGF_SC-8)
|
||||
.align 4
|
||||
.LENDFDEDLSI1:
|
||||
|
||||
.long .LENDFDEDLSI2-.LSTARTFDEDLSI2 /* Length FDE */
|
||||
.LSTARTFDEDLSI2:
|
||||
.long .LSTARTFDEDLSI2-.LSTARTFRAMEDLSI1 /* CIE pointer */
|
||||
.long .startrtsigcode-. /* PC-relative start address */
|
||||
.long .endrtsigcode-.startrtsigcode
|
||||
.uleb128 0 /* Augmentation */
|
||||
do_cfa_expr(LINUX_RT_SIGF_SC-4+LINUX_SC_ESP)
|
||||
.align 4
|
||||
.LENDFDEDLSI2:
|
||||
.previous
|
||||
|
||||
.section .eh_frame,"a",@progbits
|
||||
.LSTARTFRAMEDLSI2:
|
||||
.long .LENDCIEDLSI2-.LSTARTCIEDLSI2
|
||||
.LSTARTCIEDLSI2:
|
||||
.long 0 /* CIE ID */
|
||||
.byte 1 /* Version number */
|
||||
.string "zR" /* NULL-terminated
|
||||
* augmentation string
|
||||
*/
|
||||
.uleb128 1 /* Code alignment factor */
|
||||
.sleb128 -4 /* Data alignment factor */
|
||||
.byte 8 /* Return address register column */
|
||||
.uleb128 1 /* Augmentation value length */
|
||||
.byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
|
||||
.byte 0x0c /* DW_CFA_def_cfa */
|
||||
.uleb128 4
|
||||
.uleb128 4
|
||||
.byte 0x88 /* DW_CFA_offset, column 0x8 */
|
||||
.uleb128 1
|
||||
.align 4
|
||||
.LENDCIEDLSI2:
|
||||
.long .LENDFDEDLSI3-.LSTARTFDEDLSI3 /* Length FDE */
|
||||
.LSTARTFDEDLSI3:
|
||||
.long .LSTARTFDEDLSI3-.LSTARTFRAMEDLSI2 /* CIE pointer */
|
||||
.long .startvsyscall-. /* PC-relative start address */
|
||||
.long .endvsyscall-.startvsyscall
|
||||
.uleb128 0
|
||||
.align 4
|
||||
.LENDFDEDLSI3:
|
||||
.previous
|
||||
|
@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <compat/linux/linux_misc.h>
|
||||
#include <compat/linux/linux_signal.h>
|
||||
#include <compat/linux/linux_util.h>
|
||||
#include <compat/linux/linux_vdso.h>
|
||||
|
||||
MODULE_VERSION(linux, 1);
|
||||
|
||||
@ -111,8 +112,11 @@ MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
|
||||
|
||||
const char *linux_platform = "i686";
|
||||
static int linux_szplatform;
|
||||
extern char linux_sigcode[];
|
||||
extern int linux_szsigcode;
|
||||
static int linux_szsigcode;
|
||||
static vm_object_t linux_shared_page_obj;
|
||||
static char *linux_shared_page_mapping;
|
||||
extern char _binary_linux32_locore_o_start;
|
||||
extern char _binary_linux32_locore_o_end;
|
||||
|
||||
extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
|
||||
|
||||
@ -127,6 +131,8 @@ static void exec_linux_setregs(struct thread *td,
|
||||
struct image_params *imgp, u_long stack);
|
||||
static void linux32_fixlimit(struct rlimit *rl, int which);
|
||||
static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel);
|
||||
static void linux_vdso_install(void *param);
|
||||
static void linux_vdso_deinstall(void *param);
|
||||
|
||||
static eventhandler_tag linux_exit_tag;
|
||||
static eventhandler_tag linux_exec_tag;
|
||||
@ -220,6 +226,10 @@ struct linux32_ps_strings {
|
||||
u_int ps_nenvstr; /* the number of environment strings */
|
||||
};
|
||||
|
||||
LINUX_VDSO_SYM_INTPTR(linux32_sigcode);
|
||||
LINUX_VDSO_SYM_INTPTR(linux32_rt_sigcode);
|
||||
LINUX_VDSO_SYM_INTPTR(linux32_vsyscall);
|
||||
|
||||
/*
|
||||
* If FreeBSD & Linux have a difference of opinion about what a trap
|
||||
* means, deal with it here.
|
||||
@ -259,6 +269,9 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
|
||||
args = (Elf32_Auxargs *)imgp->auxargs;
|
||||
pos = base + (imgp->args->argc + imgp->args->envc + 2);
|
||||
|
||||
AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO_EHDR,
|
||||
imgp->proc->p_sysent->sv_shared_page_base);
|
||||
AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO, linux32_vsyscall);
|
||||
AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature);
|
||||
|
||||
/*
|
||||
@ -297,8 +310,6 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
|
||||
return (0);
|
||||
}
|
||||
|
||||
extern unsigned long linux_sznonrtsigcode;
|
||||
|
||||
static void
|
||||
linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
{
|
||||
@ -353,7 +364,8 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig);
|
||||
|
||||
/*
|
||||
* Build the signal context to be used by sigreturn.
|
||||
* Build the signal context to be used by sigreturn
|
||||
* and libgcc unwind.
|
||||
*/
|
||||
frame.sf_sc.uc_flags = 0; /* XXX ??? */
|
||||
frame.sf_sc.uc_link = 0; /* XXX ??? */
|
||||
@ -371,6 +383,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
frame.sf_sc.uc_mcontext.sc_esi = regs->tf_rsi;
|
||||
frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_rbp;
|
||||
frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_rbx;
|
||||
frame.sf_sc.uc_mcontext.sc_esp = regs->tf_rsp;
|
||||
frame.sf_sc.uc_mcontext.sc_edx = regs->tf_rdx;
|
||||
frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_rcx;
|
||||
frame.sf_sc.uc_mcontext.sc_eax = regs->tf_rax;
|
||||
@ -412,7 +425,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 = p->p_sysent->sv_sigcode_base + linux_sznonrtsigcode;
|
||||
regs->tf_rip = linux32_rt_sigcode;
|
||||
regs->tf_rflags &= ~(PSL_T | PSL_D);
|
||||
regs->tf_cs = _ucode32sel;
|
||||
regs->tf_ss = _udatasel;
|
||||
@ -507,6 +520,7 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
frame.sf_sc.sc_esi = regs->tf_rsi;
|
||||
frame.sf_sc.sc_ebp = regs->tf_rbp;
|
||||
frame.sf_sc.sc_ebx = regs->tf_rbx;
|
||||
frame.sf_sc.sc_esp = regs->tf_rsp;
|
||||
frame.sf_sc.sc_edx = regs->tf_rdx;
|
||||
frame.sf_sc.sc_ecx = regs->tf_rcx;
|
||||
frame.sf_sc.sc_eax = regs->tf_rax;
|
||||
@ -535,7 +549,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 = p->p_sysent->sv_sigcode_base;
|
||||
regs->tf_rip = linux32_sigcode;
|
||||
regs->tf_rflags &= ~(PSL_T | PSL_D);
|
||||
regs->tf_cs = _ucode32sel;
|
||||
regs->tf_ss = _udatasel;
|
||||
@ -1014,7 +1028,7 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_transtrap = translate_traps,
|
||||
.sv_fixup = elf_linux_fixup,
|
||||
.sv_sendsig = linux_sendsig,
|
||||
.sv_sigcode = linux_sigcode,
|
||||
.sv_sigcode = &_binary_linux32_locore_o_start,
|
||||
.sv_szsigcode = &linux_szsigcode,
|
||||
.sv_prepsyscall = NULL,
|
||||
.sv_name = "Linux ELF32",
|
||||
@ -1040,7 +1054,39 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_schedtail = linux_schedtail,
|
||||
.sv_thread_detach = linux_thread_detach,
|
||||
};
|
||||
INIT_SYSENTVEC(elf_sysvec, &elf_linux_sysvec);
|
||||
|
||||
static void
|
||||
linux_vdso_install(void *param)
|
||||
{
|
||||
|
||||
linux_szsigcode = (&_binary_linux32_locore_o_end -
|
||||
&_binary_linux32_locore_o_start);
|
||||
|
||||
if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len)
|
||||
panic("Linux invalid vdso size\n");
|
||||
|
||||
__elfN(linux_vdso_fixup)(&elf_linux_sysvec);
|
||||
|
||||
linux_shared_page_obj = __elfN(linux_shared_page_init)
|
||||
(&linux_shared_page_mapping);
|
||||
|
||||
__elfN(linux_vdso_reloc)(&elf_linux_sysvec, LINUX32_SHAREDPAGE);
|
||||
|
||||
bcopy(elf_linux_sysvec.sv_sigcode, linux_shared_page_mapping,
|
||||
linux_szsigcode);
|
||||
elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj;
|
||||
}
|
||||
SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC, SI_ORDER_ANY,
|
||||
(sysinit_cfunc_t)linux_vdso_install, NULL);
|
||||
|
||||
static void
|
||||
linux_vdso_deinstall(void *param)
|
||||
{
|
||||
|
||||
__elfN(linux_shared_page_fini)(linux_shared_page_obj);
|
||||
};
|
||||
SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST,
|
||||
(sysinit_cfunc_t)linux_vdso_deinstall, NULL);
|
||||
|
||||
static char GNU_ABI_VENDOR[] = "GNU";
|
||||
static int GNULINUX_ABI_DESC = 0;
|
||||
|
65
sys/amd64/linux32/linux32_vdso.lds.s
Normal file
65
sys/amd64/linux32/linux32_vdso.lds.s
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Linker script for 32-bit vDSO.
|
||||
* Copied from Linux kernel arch/x86/vdso/vdso-layout.lds.S
|
||||
* and arch/x86/vdso/vdso32/vdso32.lds.S
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = . + SIZEOF_HEADERS;
|
||||
|
||||
.hash : { *(.hash) } :text
|
||||
.gnu.hash : { *(.gnu.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
|
||||
.note : { *(.note.*) } :text :note
|
||||
|
||||
.eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
|
||||
.eh_frame : { KEEP (*(.eh_frame)) } :text
|
||||
|
||||
.dynamic : { *(.dynamic) } :text :dynamic
|
||||
|
||||
.rodata : { *(.rodata*) } :text
|
||||
.data : {
|
||||
*(.data*)
|
||||
*(.sdata*)
|
||||
*(.got.plt) *(.got)
|
||||
*(.gnu.linkonce.d.*)
|
||||
*(.bss*)
|
||||
*(.dynbss*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
}
|
||||
|
||||
.altinstructions : { *(.altinstructions) }
|
||||
.altinstr_replacement : { *(.altinstr_replacement) }
|
||||
|
||||
. = ALIGN(0x100);
|
||||
.text : { *(.text*) } :text =0x90909090
|
||||
}
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
|
||||
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
|
||||
note PT_NOTE FLAGS(4); /* PF_R */
|
||||
eh_frame_hdr PT_GNU_EH_FRAME;
|
||||
}
|
||||
|
||||
ENTRY(linux32_vsyscall);
|
||||
|
||||
VERSION
|
||||
{
|
||||
LINUX_2.5 {
|
||||
global:
|
||||
linux32_vsyscall;
|
||||
linux32_sigcode;
|
||||
linux32_rt_sigcode;
|
||||
local: *;
|
||||
};
|
||||
}
|
@ -71,6 +71,8 @@ extern const char *linux_platform;
|
||||
* differ from AT_PLATFORM.
|
||||
*/
|
||||
#define LINUX_AT_EXECFN 31 /* filename of program */
|
||||
#define LINUX_AT_SYSINFO 32 /* vsyscall */
|
||||
#define LINUX_AT_SYSINFO_EHDR 33 /* vdso header */
|
||||
|
||||
/* Linux sets the i387 to extended precision. */
|
||||
#if defined(__i386__) || defined(__amd64__)
|
||||
|
240
sys/compat/linux/linux_vdso.c
Normal file
240
sys/compat/linux/linux_vdso.c
Normal file
@ -0,0 +1,240 @@
|
||||
/*-
|
||||
* Copyright (c) 2013 Dmitry Chagin
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_compat.h"
|
||||
|
||||
#define __ELF_WORD_SIZE 32
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/elf.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/sysent.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_extern.h>
|
||||
#include <vm/vm_kern.h>
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_pager.h>
|
||||
|
||||
#include <compat/linux/linux_vdso.h>
|
||||
|
||||
SLIST_HEAD(, linux_vdso_sym) __elfN(linux_vdso_syms) =
|
||||
SLIST_HEAD_INITIALIZER(__elfN(linux_vdso_syms));
|
||||
|
||||
static int __elfN(symtabindex);
|
||||
static int __elfN(symstrindex);
|
||||
|
||||
static void
|
||||
__elfN(linux_vdso_lookup)(Elf_Ehdr *, struct linux_vdso_sym *);
|
||||
|
||||
|
||||
void
|
||||
__elfN(linux_vdso_sym_init)(struct linux_vdso_sym *s)
|
||||
{
|
||||
|
||||
SLIST_INSERT_HEAD(&__elfN(linux_vdso_syms), s, sym);
|
||||
}
|
||||
|
||||
vm_object_t
|
||||
__elfN(linux_shared_page_init)(char **mapping)
|
||||
{
|
||||
vm_page_t m;
|
||||
vm_object_t obj;
|
||||
vm_offset_t addr;
|
||||
|
||||
obj = vm_pager_allocate(OBJT_PHYS, 0, PAGE_SIZE,
|
||||
VM_PROT_DEFAULT, 0, NULL);
|
||||
VM_OBJECT_WLOCK(obj);
|
||||
m = vm_page_grab(obj, 0, VM_ALLOC_NOBUSY | VM_ALLOC_ZERO);
|
||||
m->valid = VM_PAGE_BITS_ALL;
|
||||
VM_OBJECT_WUNLOCK(obj);
|
||||
addr = kva_alloc(PAGE_SIZE);
|
||||
pmap_qenter(addr, &m, 1);
|
||||
*mapping = (char *)addr;
|
||||
return (obj);
|
||||
}
|
||||
|
||||
void
|
||||
__elfN(linux_shared_page_fini)(vm_object_t obj)
|
||||
{
|
||||
|
||||
vm_object_deallocate(obj);
|
||||
}
|
||||
|
||||
void
|
||||
__elfN(linux_vdso_fixup)(struct sysentvec *sv)
|
||||
{
|
||||
Elf_Ehdr *ehdr;
|
||||
Elf_Shdr *shdr;
|
||||
int i;
|
||||
|
||||
ehdr = (Elf_Ehdr *) sv->sv_sigcode;
|
||||
|
||||
if (!IS_ELF(*ehdr) ||
|
||||
ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
|
||||
ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
|
||||
ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
|
||||
ehdr->e_shoff == 0 ||
|
||||
ehdr->e_shentsize != sizeof(Elf_Shdr))
|
||||
panic("Linux invalid vdso header.\n");
|
||||
|
||||
if (ehdr->e_type != ET_DYN)
|
||||
panic("Linux invalid vdso header.\n");
|
||||
|
||||
shdr = (Elf_Shdr *) ((caddr_t)ehdr + ehdr->e_shoff);
|
||||
|
||||
__elfN(symtabindex) = -1;
|
||||
__elfN(symstrindex) = -1;
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
if (shdr[i].sh_size == 0)
|
||||
continue;
|
||||
if (shdr[i].sh_type == SHT_DYNSYM) {
|
||||
__elfN(symtabindex) = i;
|
||||
__elfN(symstrindex) = shdr[i].sh_link;
|
||||
}
|
||||
}
|
||||
|
||||
if (__elfN(symtabindex) == -1 || __elfN(symstrindex) == -1)
|
||||
panic("Linux invalid vdso header.\n");
|
||||
|
||||
ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX;
|
||||
}
|
||||
|
||||
void
|
||||
__elfN(linux_vdso_reloc)(struct sysentvec *sv, int vdso_adjust)
|
||||
{
|
||||
struct linux_vdso_sym *lsym;
|
||||
Elf_Ehdr *ehdr;
|
||||
Elf_Phdr *phdr;
|
||||
Elf_Shdr *shdr;
|
||||
Elf_Dyn *dyn;
|
||||
Elf_Sym *sym;
|
||||
int i, symcnt;
|
||||
|
||||
ehdr = (Elf_Ehdr *) sv->sv_sigcode;
|
||||
|
||||
/* Adjust our so relative to the sigcode_base */
|
||||
if (vdso_adjust != 0) {
|
||||
ehdr->e_entry += vdso_adjust;
|
||||
phdr = (Elf_Phdr *)((caddr_t)ehdr + ehdr->e_phoff);
|
||||
|
||||
/* phdrs */
|
||||
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||
phdr[i].p_vaddr += vdso_adjust;
|
||||
if (phdr[i].p_type != PT_DYNAMIC)
|
||||
continue;
|
||||
dyn = (Elf_Dyn *)((caddr_t)ehdr + phdr[i].p_offset);
|
||||
for(; dyn->d_tag != DT_NULL; dyn++) {
|
||||
switch (dyn->d_tag) {
|
||||
case DT_PLTGOT:
|
||||
case DT_HASH:
|
||||
case DT_STRTAB:
|
||||
case DT_SYMTAB:
|
||||
case DT_RELA:
|
||||
case DT_INIT:
|
||||
case DT_FINI:
|
||||
case DT_REL:
|
||||
case DT_DEBUG:
|
||||
case DT_JMPREL:
|
||||
case DT_VERSYM:
|
||||
case DT_VERDEF:
|
||||
case DT_VERNEED:
|
||||
case DT_ADDRRNGLO ... DT_ADDRRNGHI:
|
||||
dyn->d_un.d_ptr += vdso_adjust;
|
||||
break;
|
||||
case DT_ENCODING ... DT_LOOS-1:
|
||||
case DT_LOOS ... DT_HIOS:
|
||||
if (dyn->d_tag >= DT_ENCODING &&
|
||||
(dyn->d_tag & 1) == 0)
|
||||
dyn->d_un.d_ptr += vdso_adjust;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* sections */
|
||||
shdr = (Elf_Shdr *)((caddr_t)ehdr + ehdr->e_shoff);
|
||||
for(i = 0; i < ehdr->e_shnum; i++) {
|
||||
if (!(shdr[i].sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
shdr[i].sh_addr += vdso_adjust;
|
||||
if (shdr[i].sh_type != SHT_SYMTAB &&
|
||||
shdr[i].sh_type != SHT_DYNSYM)
|
||||
continue;
|
||||
|
||||
sym = (Elf_Sym *)((caddr_t)ehdr + shdr[i].sh_offset);
|
||||
symcnt = shdr[i].sh_size / sizeof(*sym);
|
||||
|
||||
for(i = 0; i < symcnt; i++, sym++) {
|
||||
if (sym->st_shndx == SHN_UNDEF ||
|
||||
sym->st_shndx == SHN_ABS)
|
||||
continue;
|
||||
sym->st_value += vdso_adjust;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SLIST_FOREACH(lsym, &__elfN(linux_vdso_syms), sym)
|
||||
__elfN(linux_vdso_lookup)(ehdr, lsym);
|
||||
}
|
||||
|
||||
static void
|
||||
__elfN(linux_vdso_lookup)(Elf_Ehdr *ehdr, struct linux_vdso_sym *vsym)
|
||||
{
|
||||
vm_offset_t strtab, symname;
|
||||
uint32_t symcnt;
|
||||
Elf_Shdr *shdr;
|
||||
int i;
|
||||
|
||||
shdr = (Elf_Shdr *) ((caddr_t)ehdr + ehdr->e_shoff);
|
||||
|
||||
strtab = (vm_offset_t)((caddr_t)ehdr +
|
||||
shdr[__elfN(symstrindex)].sh_offset);
|
||||
Elf_Sym *sym = (Elf_Sym *)((caddr_t)ehdr +
|
||||
shdr[__elfN(symtabindex)].sh_offset);
|
||||
symcnt = shdr[__elfN(symtabindex)].sh_size / sizeof(*sym);
|
||||
|
||||
for (i = 0; i < symcnt; ++i, ++sym) {
|
||||
symname = strtab + sym->st_name;
|
||||
if (strncmp(vsym->symname, (char *)symname, vsym->size) == 0) {
|
||||
*vsym->ptr = (uintptr_t)sym->st_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
65
sys/compat/linux/linux_vdso.h
Normal file
65
sys/compat/linux/linux_vdso.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*-
|
||||
* Copyright (c) 2013 Dmitry Chagin
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_VDSO_H_
|
||||
#define _LINUX_VDSO_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct linux_vdso_sym {
|
||||
SLIST_ENTRY(linux_vdso_sym) sym;
|
||||
uint32_t size;
|
||||
uintptr_t * ptr;
|
||||
char symname[];
|
||||
};
|
||||
|
||||
vm_object_t __elfN(linux_shared_page_init)(char **);
|
||||
void __elfN(linux_shared_page_fini)(vm_object_t);
|
||||
void __elfN(linux_vdso_fixup)(struct sysentvec *);
|
||||
void __elfN(linux_vdso_reloc)(struct sysentvec *, int);
|
||||
void __elfN(linux_vdso_sym_init)(struct linux_vdso_sym *);
|
||||
|
||||
#define LINUX_VDSO_SYM_INTPTR(name) \
|
||||
uintptr_t name; \
|
||||
LINUX_VDSO_SYM_DEFINE(name)
|
||||
|
||||
#define LINUX_VDSO_SYM_CHAR(name) \
|
||||
const char * name; \
|
||||
LINUX_VDSO_SYM_DEFINE(name)
|
||||
|
||||
#define LINUX_VDSO_SYM_DEFINE(name) \
|
||||
static struct linux_vdso_sym name ## sym = { \
|
||||
.symname = #name, \
|
||||
.size = sizeof(#name), \
|
||||
.ptr = (uintptr_t *)&name \
|
||||
}; \
|
||||
SYSINIT(__elfN(name ## _sym_init), SI_SUB_EXEC, \
|
||||
SI_ORDER_FIRST, __elfN(linux_vdso_sym_init), &name ## sym); \
|
||||
struct __hack
|
||||
|
||||
#endif /* _LINUX_VDSO_H_ */
|
@ -20,6 +20,18 @@ linux32_assym.h optional compat_linux32 \
|
||||
no-obj no-implicit-rule before-depend \
|
||||
clean "linux32_assym.h"
|
||||
#
|
||||
linux32_locore.o optional compat_linux32 \
|
||||
dependency "linux32_assym.h $S/amd64/linux32/linux32_locore.s" \
|
||||
compile-with "${CC} -x assembler-with-cpp -DLOCORE -m32 -shared -s -pipe -I. -I$S -Werror -Wall -fno-common -nostdinc -nostdlib -Wl,-T$S/amd64/linux32/linux32_vdso.lds.s -Wl,-soname=linux32_vdso.so,--eh-frame-hdr,-fPIC,-warn-common ${.IMPSRC} -o ${.TARGET}" \
|
||||
no-obj no-implicit-rule \
|
||||
clean "linux32_locore.o"
|
||||
#
|
||||
linux32_vdso.so optional compat_linux32 \
|
||||
dependency "linux32_locore.o" \
|
||||
compile-with "${OBJCOPY} --input binary --output elf64-x86-64-freebsd --binary-architecture i386 linux32_locore.o ${.TARGET}" \
|
||||
no-implicit-rule \
|
||||
clean "linux32_vdso.so"
|
||||
#
|
||||
ia32_genassym.o standard \
|
||||
dependency "$S/compat/ia32/ia32_genassym.c" \
|
||||
compile-with "${CC} ${CFLAGS:N-fno-common} -c ${.IMPSRC}" \
|
||||
@ -473,8 +485,6 @@ compat/linsysfs/linsysfs.c optional linsysfs
|
||||
# Linux/i386 binary support
|
||||
#
|
||||
amd64/linux32/linux32_dummy.c optional compat_linux32
|
||||
amd64/linux32/linux32_locore.s optional compat_linux32 \
|
||||
dependency "linux32_assym.h"
|
||||
amd64/linux32/linux32_machdep.c optional compat_linux32
|
||||
amd64/linux32/linux32_support.s optional compat_linux32 \
|
||||
dependency "linux32_assym.h"
|
||||
@ -497,6 +507,7 @@ compat/linux/linux_time.c optional compat_linux32
|
||||
compat/linux/linux_timer.c optional compat_linux32
|
||||
compat/linux/linux_uid16.c optional compat_linux32
|
||||
compat/linux/linux_util.c optional compat_linux32
|
||||
compat/linux/linux_vdso.c optional compat_linux32
|
||||
dev/amr/amr_linux.c optional compat_linux32 amr
|
||||
dev/mfi/mfi_linux.c optional compat_linux32 mfi
|
||||
#
|
||||
|
@ -19,6 +19,18 @@ linux_assym.h optional compat_linux \
|
||||
no-obj no-implicit-rule before-depend \
|
||||
clean "linux_assym.h"
|
||||
#
|
||||
linux_locore.o optional compat_linux \
|
||||
dependency "linux_assym.h $S/i386/linux/linux_locore.s" \
|
||||
compile-with "${CC} -x assembler-with-cpp -DLOCORE -shared -s -pipe -I. -I$S -Werror -Wall -fno-common -nostdinc -nostdlib -Wl,-T$S/i386/linux/linux_vdso.lds.s -Wl,-soname=linux_vdso.so,--eh-frame-hdr,-fPIC,-warn-common ${.IMPSRC} -o ${.TARGET}" \
|
||||
no-obj no-implicit-rule \
|
||||
clean "linux_locore.o"
|
||||
#
|
||||
linux_vdso.so optional compat_linux \
|
||||
dependency "linux_locore.o" \
|
||||
compile-with "${OBJCOPY} --input binary --output elf32-i386-freebsd --binary-architecture i386 linux_locore.o ${.TARGET}" \
|
||||
no-implicit-rule \
|
||||
clean "linux_vdso.so"
|
||||
#
|
||||
svr4_genassym.o optional compat_svr4 \
|
||||
dependency "$S/i386/svr4/svr4_genassym.c" \
|
||||
compile-with "${CC} ${CFLAGS:N-fno-common} -c ${.IMPSRC}" \
|
||||
@ -86,6 +98,7 @@ compat/linux/linux_time.c optional compat_linux
|
||||
compat/linux/linux_timer.c optional compat_linux
|
||||
compat/linux/linux_uid16.c optional compat_linux
|
||||
compat/linux/linux_util.c optional compat_linux
|
||||
compat/linux/linux_vdso.c optional compat_linux
|
||||
compat/ndis/kern_ndis.c optional ndisapi pci
|
||||
compat/ndis/kern_windrv.c optional ndisapi pci
|
||||
compat/ndis/subr_hal.c optional ndisapi pci
|
||||
@ -490,8 +503,6 @@ i386/isa/prof_machdep.c optional profiling-routine
|
||||
i386/isa/spic.c optional spic
|
||||
i386/linux/imgact_linux.c optional compat_linux
|
||||
i386/linux/linux_dummy.c optional compat_linux
|
||||
i386/linux/linux_locore.s optional compat_linux \
|
||||
dependency "linux_assym.h"
|
||||
i386/linux/linux_machdep.c optional compat_linux
|
||||
i386/linux/linux_ptrace.c optional compat_linux
|
||||
i386/linux/linux_support.s optional compat_linux \
|
||||
|
@ -108,7 +108,7 @@ typedef struct {
|
||||
/*
|
||||
* Miscellaneous
|
||||
*/
|
||||
#define LINUX_AT_COUNT 16 /* Count of used aux entry types.
|
||||
#define LINUX_AT_COUNT 18 /* Count of used aux entry types.
|
||||
* Keep this synchronized with
|
||||
* elf_linux_fixup() code.
|
||||
*/
|
||||
|
@ -6,6 +6,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/systm.h>
|
||||
|
||||
#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));
|
||||
@ -14,3 +15,5 @@ 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));
|
||||
ASSYM(LINUX_VERSION_CODE, LINUX_VERSION_CODE);
|
||||
|
@ -5,33 +5,145 @@
|
||||
|
||||
#include <i386/linux/linux_syscall.h> /* system call numbers */
|
||||
|
||||
#include "assym.s"
|
||||
|
||||
/*
|
||||
* To avoid excess stack frame the signal trampoline code emulates
|
||||
* the 'call' instruction.
|
||||
*/
|
||||
NON_GPROF_ENTRY(linux_sigcode)
|
||||
call *LINUX_SIGF_HANDLER(%esp)
|
||||
leal LINUX_SIGF_SC(%esp),%ebx /* linux scp */
|
||||
mov LINUX_SC_GS(%ebx),%gs
|
||||
movl %esp, %ebx /* pass sigframe */
|
||||
push %eax /* fake ret addr */
|
||||
movl %esp, %ebx /* preserve sigframe */
|
||||
call .getip0
|
||||
.getip0:
|
||||
popl %eax
|
||||
add $.startsigcode-.getip0, %eax /* ret address */
|
||||
push %eax
|
||||
jmp *LINUX_SIGF_HANDLER(%ebx)
|
||||
.startsigcode:
|
||||
popl %eax /* gcc unwind code need this */
|
||||
movl $LINUX_SYS_linux_sigreturn,%eax /* linux_sigreturn() */
|
||||
int $0x80 /* enter kernel with args */
|
||||
.endsigcode:
|
||||
0: jmp 0b
|
||||
ALIGN_TEXT
|
||||
/* XXXXX */
|
||||
linux_rt_sigcode:
|
||||
call *LINUX_RT_SIGF_HANDLER(%esp)
|
||||
|
||||
NON_GPROF_ENTRY(linux_rt_sigcode)
|
||||
leal LINUX_RT_SIGF_UC(%esp),%ebx /* linux ucp */
|
||||
leal LINUX_RT_SIGF_SC(%ebx),%ecx /* linux sigcontext */
|
||||
mov LINUX_SC_GS(%ecx),%gs
|
||||
push %eax /* fake ret addr */
|
||||
movl %esp, %edi
|
||||
call .getip1
|
||||
.getip1:
|
||||
popl %eax
|
||||
add $.startrtsigcode-.getip1, %eax /* ret address */
|
||||
push %eax
|
||||
jmp *LINUX_RT_SIGF_HANDLER(%edi)
|
||||
.startrtsigcode:
|
||||
movl $LINUX_SYS_linux_rt_sigreturn,%eax /* linux_rt_sigreturn() */
|
||||
int $0x80 /* enter kernel with args */
|
||||
.endrtsigcode:
|
||||
0: jmp 0b
|
||||
ALIGN_TEXT
|
||||
/* XXXXX */
|
||||
linux_esigcode:
|
||||
|
||||
.data
|
||||
.globl linux_szsigcode, linux_sznonrtsigcode
|
||||
linux_szsigcode:
|
||||
.long linux_esigcode-linux_sigcode
|
||||
linux_sznonrtsigcode:
|
||||
.long linux_rt_sigcode-linux_sigcode
|
||||
NON_GPROF_ENTRY(linux_vsyscall)
|
||||
.startvsyscall:
|
||||
int $0x80
|
||||
ret
|
||||
.endvsyscall:
|
||||
|
||||
|
||||
.section .note.Linux, "a",@note
|
||||
.long 2f - 1f /* namesz */
|
||||
.balign 4
|
||||
.long 4f - 3f /* descsz */
|
||||
.long 0
|
||||
1:
|
||||
.asciz "Linux"
|
||||
2:
|
||||
.balign 4
|
||||
3:
|
||||
.long LINUX_VERSION_CODE
|
||||
4:
|
||||
.balign 4
|
||||
.previous
|
||||
|
||||
|
||||
#define do_cfa_expr(offset) \
|
||||
.byte 0x0f; /* DW_CFA_def_cfa_expression */ \
|
||||
.uleb128 11f-10f; /* length */ \
|
||||
10: .byte 0x74; /* DW_OP_breg4 */ \
|
||||
.sleb128 offset; /* offset */ \
|
||||
.byte 0x06; /* DW_OP_deref */ \
|
||||
11:
|
||||
|
||||
|
||||
/* CIE */
|
||||
.section .eh_frame,"a",@progbits
|
||||
.LSTARTFRAMEDLSI1:
|
||||
.long .LENDCIEDLSI1-.LSTARTCIEDLSI1
|
||||
.LSTARTCIEDLSI1:
|
||||
.long 0 /* CIE ID */
|
||||
.byte 1 /* Version number */
|
||||
.string "zRS" /* NULL-terminated
|
||||
* augmentation string
|
||||
*/
|
||||
.uleb128 1 /* Code alignment factor */
|
||||
.sleb128 -4 /* Data alignment factor */
|
||||
.byte 8 /* Return address
|
||||
* register column
|
||||
*/
|
||||
.uleb128 1 /* Augmentation value length */
|
||||
.byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
|
||||
.byte 0 /* DW_CFA_nop */
|
||||
.align 4
|
||||
.LENDCIEDLSI1:
|
||||
|
||||
/* FDE */
|
||||
.long .LENDFDEDLSI1-.LSTARTFDEDLSI1 /* Length FDE */
|
||||
.LSTARTFDEDLSI1:
|
||||
.long .LSTARTFDEDLSI1-.LSTARTFRAMEDLSI1 /* CIE pointer */
|
||||
.long .startsigcode-. /* PC-relative start address */
|
||||
.long .endsigcode-.startsigcode
|
||||
.uleb128 0 /* Augmentation */
|
||||
do_cfa_expr(LINUX_SIGF_SC-8)
|
||||
.align 4
|
||||
.LENDFDEDLSI1:
|
||||
|
||||
.long .LENDFDEDLSI2-.LSTARTFDEDLSI2 /* Length FDE */
|
||||
.LSTARTFDEDLSI2:
|
||||
.long .LSTARTFDEDLSI2-.LSTARTFRAMEDLSI1 /* CIE pointer */
|
||||
.long .startrtsigcode-. /* PC-relative start address */
|
||||
.long .endrtsigcode-.startrtsigcode
|
||||
.uleb128 0 /* Augmentation */
|
||||
do_cfa_expr(LINUX_RT_SIGF_SC-4+LINUX_SC_ESP)
|
||||
.align 4
|
||||
.LENDFDEDLSI2:
|
||||
.previous
|
||||
|
||||
.section .eh_frame,"a",@progbits
|
||||
.LSTARTFRAMEDLSI2:
|
||||
.long .LENDCIEDLSI2-.LSTARTCIEDLSI2
|
||||
.LSTARTCIEDLSI2:
|
||||
.long 0 /* CIE ID */
|
||||
.byte 1 /* Version number */
|
||||
.string "zR" /* NULL-terminated
|
||||
* augmentation string
|
||||
*/
|
||||
.uleb128 1 /* Code alignment factor */
|
||||
.sleb128 -4 /* Data alignment factor */
|
||||
.byte 8 /* Return address register column */
|
||||
.uleb128 1 /* Augmentation value length */
|
||||
.byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
|
||||
.byte 0x0c /* DW_CFA_def_cfa */
|
||||
.uleb128 4
|
||||
.uleb128 4
|
||||
.byte 0x88 /* DW_CFA_offset, column 0x8 */
|
||||
.uleb128 1
|
||||
.align 4
|
||||
.LENDCIEDLSI2:
|
||||
.long .LENDFDEDLSI3-.LSTARTFDEDLSI3 /* Length FDE */
|
||||
.LSTARTFDEDLSI3:
|
||||
.long .LSTARTFDEDLSI3-.LSTARTFRAMEDLSI2 /* CIE pointer */
|
||||
.long .startvsyscall-. /* PC-relative start address */
|
||||
.long .endvsyscall-.startvsyscall
|
||||
.uleb128 0
|
||||
.align 4
|
||||
.LENDFDEDLSI3:
|
||||
.previous
|
||||
|
@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <compat/linux/linux_misc.h>
|
||||
#include <compat/linux/linux_signal.h>
|
||||
#include <compat/linux/linux_util.h>
|
||||
#include <compat/linux/linux_vdso.h>
|
||||
|
||||
MODULE_VERSION(linux, 1);
|
||||
|
||||
@ -93,8 +94,11 @@ MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
|
||||
|
||||
#define LINUX_PS_STRINGS (LINUX_USRSTACK - sizeof(struct ps_strings))
|
||||
|
||||
extern char linux_sigcode[];
|
||||
extern int linux_szsigcode;
|
||||
static int linux_szsigcode;
|
||||
static vm_object_t linux_shared_page_obj;
|
||||
static char *linux_shared_page_mapping;
|
||||
extern char _binary_linux_locore_o_start;
|
||||
extern char _binary_linux_locore_o_end;
|
||||
|
||||
extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
|
||||
|
||||
@ -110,6 +114,8 @@ static void exec_linux_setregs(struct thread *td,
|
||||
struct image_params *imgp, u_long stack);
|
||||
static register_t *linux_copyout_strings(struct image_params *imgp);
|
||||
static boolean_t linux_trans_osrel(const Elf_Note *note, int32_t *osrel);
|
||||
static void linux_vdso_install(void *param);
|
||||
static void linux_vdso_deinstall(void *param);
|
||||
|
||||
static int linux_szplatform;
|
||||
const char *linux_platform;
|
||||
@ -199,6 +205,10 @@ static int _bsd_to_linux_trapcode[] = {
|
||||
_bsd_to_linux_trapcode[(code)]: \
|
||||
LINUX_T_UNKNOWN)
|
||||
|
||||
LINUX_VDSO_SYM_INTPTR(linux_sigcode);
|
||||
LINUX_VDSO_SYM_INTPTR(linux_rt_sigcode);
|
||||
LINUX_VDSO_SYM_INTPTR(linux_vsyscall);
|
||||
|
||||
/*
|
||||
* If FreeBSD & Linux have a difference of opinion about what a trap
|
||||
* means, deal with it here.
|
||||
@ -255,6 +265,9 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
|
||||
args = (Elf32_Auxargs *)imgp->auxargs;
|
||||
pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
|
||||
|
||||
AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR,
|
||||
imgp->proc->p_sysent->sv_shared_page_base);
|
||||
AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO, linux_vsyscall);
|
||||
AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature);
|
||||
|
||||
/*
|
||||
@ -399,10 +412,6 @@ linux_copyout_strings(struct image_params *imgp)
|
||||
return (stack_base);
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern unsigned long linux_sznonrtsigcode;
|
||||
|
||||
static void
|
||||
linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
{
|
||||
@ -478,6 +487,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
frame.sf_sc.uc_mcontext.sc_esi = regs->tf_esi;
|
||||
frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_ebp;
|
||||
frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_ebx;
|
||||
frame.sf_sc.uc_mcontext.sc_esp = regs->tf_esp;
|
||||
frame.sf_sc.uc_mcontext.sc_edx = regs->tf_edx;
|
||||
frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_ecx;
|
||||
frame.sf_sc.uc_mcontext.sc_eax = regs->tf_eax;
|
||||
@ -515,7 +525,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 = p->p_sysent->sv_sigcode_base + linux_sznonrtsigcode;
|
||||
regs->tf_eip = linux_rt_sigcode;
|
||||
regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D);
|
||||
regs->tf_cs = _ucodesel;
|
||||
regs->tf_ds = _udatasel;
|
||||
@ -606,6 +616,7 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
frame.sf_sc.sc_esi = regs->tf_esi;
|
||||
frame.sf_sc.sc_ebp = regs->tf_ebp;
|
||||
frame.sf_sc.sc_ebx = regs->tf_ebx;
|
||||
frame.sf_sc.sc_esp = regs->tf_esp;
|
||||
frame.sf_sc.sc_edx = regs->tf_edx;
|
||||
frame.sf_sc.sc_ecx = regs->tf_ecx;
|
||||
frame.sf_sc.sc_eax = regs->tf_eax;
|
||||
@ -634,7 +645,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 = p->p_sysent->sv_sigcode_base;
|
||||
regs->tf_eip = linux_sigcode;
|
||||
regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D);
|
||||
regs->tf_cs = _ucodesel;
|
||||
regs->tf_ds = _udatasel;
|
||||
@ -950,7 +961,7 @@ struct sysentvec linux_sysvec = {
|
||||
.sv_transtrap = translate_traps,
|
||||
.sv_fixup = linux_fixup,
|
||||
.sv_sendsig = linux_sendsig,
|
||||
.sv_sigcode = linux_sigcode,
|
||||
.sv_sigcode = &_binary_linux_locore_o_start,
|
||||
.sv_szsigcode = &linux_szsigcode,
|
||||
.sv_prepsyscall = NULL,
|
||||
.sv_name = "Linux a.out",
|
||||
@ -989,7 +1000,7 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_transtrap = translate_traps,
|
||||
.sv_fixup = elf_linux_fixup,
|
||||
.sv_sendsig = linux_sendsig,
|
||||
.sv_sigcode = linux_sigcode,
|
||||
.sv_sigcode = &_binary_linux_locore_o_start,
|
||||
.sv_szsigcode = &linux_szsigcode,
|
||||
.sv_prepsyscall = NULL,
|
||||
.sv_name = "Linux ELF",
|
||||
@ -1015,7 +1026,39 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_schedtail = linux_schedtail,
|
||||
.sv_thread_detach = linux_thread_detach,
|
||||
};
|
||||
INIT_SYSENTVEC(elf_sysvec, &elf_linux_sysvec);
|
||||
|
||||
static void
|
||||
linux_vdso_install(void *param)
|
||||
{
|
||||
|
||||
linux_szsigcode = (&_binary_linux_locore_o_end -
|
||||
&_binary_linux_locore_o_start);
|
||||
|
||||
if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len)
|
||||
panic("Linux invalid vdso size\n");
|
||||
|
||||
__elfN(linux_vdso_fixup)(&elf_linux_sysvec);
|
||||
|
||||
linux_shared_page_obj = __elfN(linux_shared_page_init)
|
||||
(&linux_shared_page_mapping);
|
||||
|
||||
__elfN(linux_vdso_reloc)(&elf_linux_sysvec, LINUX_SHAREDPAGE);
|
||||
|
||||
bcopy(elf_linux_sysvec.sv_sigcode, linux_shared_page_mapping,
|
||||
linux_szsigcode);
|
||||
elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj;
|
||||
}
|
||||
SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC, SI_ORDER_ANY,
|
||||
(sysinit_cfunc_t)linux_vdso_install, NULL);
|
||||
|
||||
static void
|
||||
linux_vdso_deinstall(void *param)
|
||||
{
|
||||
|
||||
__elfN(linux_shared_page_fini)(linux_shared_page_obj);
|
||||
};
|
||||
SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST,
|
||||
(sysinit_cfunc_t)linux_vdso_deinstall, NULL);
|
||||
|
||||
static char GNU_ABI_VENDOR[] = "GNU";
|
||||
static int GNULINUX_ABI_DESC = 0;
|
||||
|
65
sys/i386/linux/linux_vdso.lds.s
Normal file
65
sys/i386/linux/linux_vdso.lds.s
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Linker script for 32-bit vDSO.
|
||||
* Copied from Linux kernel arch/x86/vdso/vdso-layout.lds.S
|
||||
* and arch/x86/vdso/vdso32/vdso32.lds.S
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = . + SIZEOF_HEADERS;
|
||||
|
||||
.hash : { *(.hash) } :text
|
||||
.gnu.hash : { *(.gnu.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
|
||||
.note : { *(.note.*) } :text :note
|
||||
|
||||
.eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
|
||||
.eh_frame : { KEEP (*(.eh_frame)) } :text
|
||||
|
||||
.dynamic : { *(.dynamic) } :text :dynamic
|
||||
|
||||
.rodata : { *(.rodata*) } :text
|
||||
.data : {
|
||||
*(.data*)
|
||||
*(.sdata*)
|
||||
*(.got.plt) *(.got)
|
||||
*(.gnu.linkonce.d.*)
|
||||
*(.bss*)
|
||||
*(.dynbss*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
}
|
||||
|
||||
.altinstructions : { *(.altinstructions) }
|
||||
.altinstr_replacement : { *(.altinstr_replacement) }
|
||||
|
||||
. = ALIGN(0x100);
|
||||
.text : { *(.text*) } :text =0x90909090
|
||||
}
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
|
||||
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
|
||||
note PT_NOTE FLAGS(4); /* PF_R */
|
||||
eh_frame_hdr PT_GNU_EH_FRAME;
|
||||
}
|
||||
|
||||
ENTRY(linux_vsyscall);
|
||||
|
||||
VERSION
|
||||
{
|
||||
LINUX_2.5 {
|
||||
global:
|
||||
linux_vsyscall;
|
||||
linux_sigcode;
|
||||
linux_rt_sigcode;
|
||||
local: *;
|
||||
};
|
||||
}
|
@ -7,16 +7,18 @@ CFLAGS+=-DCOMPAT_FREEBSD32 -DCOMPAT_LINUX32
|
||||
|
||||
.PATH: ${.CURDIR}/../../compat/linux ${.CURDIR}/../../${MACHINE_CPUARCH}/linux${SFX}
|
||||
|
||||
VDSO= linux${SFX}_vdso
|
||||
|
||||
KMOD= linux
|
||||
SRCS= linux_fork.c linux${SFX}_dummy.c linux_emul.c linux_file.c \
|
||||
linux_futex.c linux_getcwd.c linux_ioctl.c linux_ipc.c \
|
||||
linux${SFX}_machdep.c linux_mib.c linux_misc.c linux_signal.c \
|
||||
linux_socket.c linux_stats.c linux_sysctl.c linux${SFX}_sysent.c \
|
||||
linux${SFX}_sysvec.c linux_uid16.c linux_util.c linux_time.c \
|
||||
linux_timer.c \
|
||||
linux_timer.c linux_vdso.c \
|
||||
opt_inet6.h opt_compat.h opt_posix.h opt_usb.h vnode_if.h \
|
||||
device_if.h bus_if.h assym.s \
|
||||
linux${SFX}_locore.s linux${SFX}_support.s
|
||||
linux${SFX}_support.s
|
||||
DPSRCS= linux${SFX}_genassym.c
|
||||
|
||||
# XXX: for assym.s
|
||||
@ -25,6 +27,8 @@ SRCS+= opt_kstack_pages.h opt_nfs.h opt_compat.h opt_hwpmc_hooks.h
|
||||
SRCS+= opt_apic.h
|
||||
.endif
|
||||
|
||||
OBJS= ${VDSO}.so
|
||||
|
||||
.if ${MACHINE_CPUARCH} == "i386"
|
||||
SRCS+= linux_ptrace.c imgact_linux.c opt_cpu.h
|
||||
.endif
|
||||
@ -37,19 +41,33 @@ EXPORT_SYMS+= linux_ifname
|
||||
EXPORT_SYMS+= linux_ioctl_register_handler
|
||||
EXPORT_SYMS+= linux_ioctl_unregister_handler
|
||||
|
||||
CLEANFILES= linux${SFX}_assym.h linux${SFX}_genassym.o
|
||||
CLEANFILES= linux${SFX}_assym.h linux${SFX}_genassym.o linux${SFX}_locore.o
|
||||
|
||||
linux${SFX}_assym.h: linux${SFX}_genassym.o
|
||||
sh ${SYSDIR}/kern/genassym.sh linux${SFX}_genassym.o > ${.TARGET}
|
||||
|
||||
linux${SFX}_locore.o: linux${SFX}_assym.h assym.s
|
||||
${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \
|
||||
${CC} -x assembler-with-cpp -DLOCORE -m32 -shared -s \
|
||||
-pipe -I. -I${SYSDIR} -Werror -Wall -fno-common -nostdinc -nostdlib \
|
||||
-fno-omit-frame-pointer \
|
||||
-Wl,-T${.CURDIR}/../../${MACHINE_CPUARCH}/linux${SFX}/${VDSO}.lds.s \
|
||||
-Wl,-soname=${VDSO}.so.1,--eh-frame-hdr,-fPIC,-warn-common \
|
||||
${.IMPSRC} -o ${.TARGET}
|
||||
|
||||
linux${SFX}_support.o: linux${SFX}_assym.h assym.s
|
||||
${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \
|
||||
${.IMPSRC} -o ${.TARGET}
|
||||
|
||||
.if ${MACHINE_CPUARCH} == "amd64"
|
||||
${VDSO}.so: linux${SFX}_locore.o
|
||||
${OBJCOPY} --input binary --output elf64-x86-64-freebsd \
|
||||
--binary-architecture i386 linux${SFX}_locore.o ${.TARGET}
|
||||
.else
|
||||
${VDSO}.so: linux${SFX}_locore.o
|
||||
${OBJCOPY} --input binary --output elf32-i386-freebsd \
|
||||
--binary-architecture i386 linux${SFX}_locore.o ${.TARGET}
|
||||
.endif
|
||||
|
||||
linux${SFX}_genassym.o:
|
||||
${CC} -c ${CFLAGS:N-fno-common} ${.IMPSRC}
|
||||
|
||||
@ -57,6 +75,9 @@ linux${SFX}_genassym.o:
|
||||
.if defined(KTR)
|
||||
CFLAGS+= -DKTR
|
||||
.endif
|
||||
.if defined(DEBUG)
|
||||
CFLAGS+= -DDEBUG
|
||||
.endif
|
||||
.endif
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
Loading…
x
Reference in New Issue
Block a user