Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F146586388
D1060.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
39 KB
Referenced Files
None
Subscribers
None
D1060.id.diff
View Options
Index: head/sys/amd64/linux32/linux.h
===================================================================
--- head/sys/amd64/linux32/linux.h
+++ head/sys/amd64/linux32/linux.h
@@ -114,7 +114,7 @@
/*
* 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.
*/
Index: head/sys/amd64/linux32/linux32_genassym.c
===================================================================
--- head/sys/amd64/linux32/linux32_genassym.c
+++ head/sys/amd64/linux32/linux32_genassym.c
@@ -7,9 +7,12 @@
#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));
Index: head/sys/amd64/linux32/linux32_locore.s
===================================================================
--- head/sys/amd64/linux32/linux32_locore.s
+++ head/sys/amd64/linux32/linux32_locore.s
@@ -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
Index: head/sys/amd64/linux32/linux32_sysvec.c
===================================================================
--- head/sys/amd64/linux32/linux32_sysvec.c
+++ head/sys/amd64/linux32/linux32_sysvec.c
@@ -83,6 +83,7 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
* 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 @@
.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 @@
.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;
Index: head/sys/amd64/linux32/linux32_vdso.lds.s
===================================================================
--- head/sys/amd64/linux32/linux32_vdso.lds.s
+++ head/sys/amd64/linux32/linux32_vdso.lds.s
@@ -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: *;
+ };
+}
Index: head/sys/compat/linux/linux_misc.h
===================================================================
--- head/sys/compat/linux/linux_misc.h
+++ head/sys/compat/linux/linux_misc.h
@@ -71,6 +71,8 @@
* 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__)
Index: head/sys/compat/linux/linux_vdso.h
===================================================================
--- head/sys/compat/linux/linux_vdso.h
+++ head/sys/compat/linux/linux_vdso.h
@@ -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_ */
Index: head/sys/compat/linux/linux_vdso.c
===================================================================
--- head/sys/compat/linux/linux_vdso.c
+++ head/sys/compat/linux/linux_vdso.c
@@ -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;
+ }
+ }
+}
Index: head/sys/conf/files.amd64
===================================================================
--- head/sys/conf/files.amd64
+++ head/sys/conf/files.amd64
@@ -20,6 +20,18 @@
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 @@
# 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_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
#
Index: head/sys/conf/files.i386
===================================================================
--- head/sys/conf/files.i386
+++ head/sys/conf/files.i386
@@ -19,6 +19,18 @@
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_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/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 \
Index: head/sys/i386/linux/linux.h
===================================================================
--- head/sys/i386/linux/linux.h
+++ head/sys/i386/linux/linux.h
@@ -108,7 +108,7 @@
/*
* 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.
*/
Index: head/sys/i386/linux/linux_genassym.c
===================================================================
--- head/sys/i386/linux/linux_genassym.c
+++ head/sys/i386/linux/linux_genassym.c
@@ -6,6 +6,7 @@
#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_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);
Index: head/sys/i386/linux/linux_locore.s
===================================================================
--- head/sys/i386/linux/linux_locore.s
+++ head/sys/i386/linux/linux_locore.s
@@ -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
Index: head/sys/i386/linux/linux_sysvec.c
===================================================================
--- head/sys/i386/linux/linux_sysvec.c
+++ head/sys/i386/linux/linux_sysvec.c
@@ -71,6 +71,7 @@
#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 @@
#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 @@
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 @@
_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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
* 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 @@
.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 @@
.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 @@
.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;
Index: head/sys/i386/linux/linux_vdso.lds.s
===================================================================
--- head/sys/i386/linux/linux_vdso.lds.s
+++ head/sys/i386/linux/linux_vdso.lds.s
@@ -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: *;
+ };
+}
Index: head/sys/modules/linux/Makefile
===================================================================
--- head/sys/modules/linux/Makefile
+++ head/sys/modules/linux/Makefile
@@ -7,16 +7,18 @@
.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_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_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 @@
.if defined(KTR)
CFLAGS+= -DKTR
.endif
+.if defined(DEBUG)
+CFLAGS+= -DDEBUG
+.endif
.endif
.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Mar 4, 9:18 PM (9 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29256588
Default Alt Text
D1060.id.diff (39 KB)
Attached To
Mode
D1060: 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...
Attached
Detach File
Event Timeline
Log In to Comment