svn commit: r365431 - head/sys/powerpc/powerpc

Brandon Bergren bdragon at FreeBSD.org
Mon Sep 7 20:25:55 UTC 2020


Author: bdragon
Date: Mon Sep  7 20:25:54 2020
New Revision: 365431
URL: https://svnweb.freebsd.org/changeset/base/365431

Log:
  [PowerPC] Initialize ELFv1 as a secondary sysvec to ELFv2.
  
  In order to enable VDSO timekeeping, it is necessary that there be exactly
  one primary FreeBSD sysvec for each of the host and (optionally) compat32.
  
  So, switch ELFv1 to being a secondary sysvec of ELFv2, so it does not get
  double-allocated in the shared page.
  
  Since secondary sysvecs use the same sigcode allocation as the primary,
  define both to use the main sigcode64, and adjust the sv_sigcode_base on
  ELFv2 after initialization to point to the correct offset.
  
  This has the desirable side effect of avoiding having a separate copy of
  the signal trampoline in the shared page. Our sigcode64 was already written
  to take advantage of trampoline sharing, it was just not being allocated
  that way until now.
  
  Submitted by:	jhibbits
  Sponsored by:	Tag1 Consulting, Inc.

Modified:
  head/sys/powerpc/powerpc/elf64_machdep.c

Modified: head/sys/powerpc/powerpc/elf64_machdep.c
==============================================================================
--- head/sys/powerpc/powerpc/elf64_machdep.c	Mon Sep  7 20:17:13 2020	(r365430)
+++ head/sys/powerpc/powerpc/elf64_machdep.c	Mon Sep  7 20:25:54 2020	(r365431)
@@ -95,7 +95,6 @@ struct sysentvec elf64_freebsd_sysvec_v1 = {
 	.sv_hwcap	= &cpu_features,
 	.sv_hwcap2	= &cpu_features2,
 };
-INIT_SYSENTVEC(elf64_sysvec_v1, &elf64_freebsd_sysvec_v1);
 
 struct sysentvec elf64_freebsd_sysvec_v2 = {
 	.sv_size	= SYS_MAXSYSCALL,
@@ -105,8 +104,8 @@ struct sysentvec elf64_freebsd_sysvec_v2 = {
 	.sv_transtrap	= NULL,
 	.sv_fixup	= __elfN(freebsd_fixup),
 	.sv_sendsig	= sendsig,
-	.sv_sigcode	= sigcode64_elfv2,
-	.sv_szsigcode	= &szsigcode64_elfv2,
+	.sv_sigcode	= sigcode64, /* Fixed up in ppc64_init_sysvecs(). */
+	.sv_szsigcode	= &szsigcode64,
 	.sv_name	= "FreeBSD ELF64 V2",
 	.sv_coredump	= __elfN(coredump),
 	.sv_imgact_try	= NULL,
@@ -133,7 +132,6 @@ struct sysentvec elf64_freebsd_sysvec_v2 = {
 	.sv_hwcap	= &cpu_features,
 	.sv_hwcap2	= &cpu_features2,
 };
-INIT_SYSENTVEC(elf64_sysvec_v2, &elf64_freebsd_sysvec_v2);
 
 static boolean_t ppc64_elfv1_header_match(struct image_params *params,
     int32_t *, uint32_t *);
@@ -192,6 +190,26 @@ SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
 	&freebsd_brand_oinfo);
 
 void elf_reloc_self(Elf_Dyn *dynp, Elf_Addr relocbase);
+
+static void
+ppc64_init_sysvecs(void *arg)
+{
+	exec_sysvec_init(&elf64_freebsd_sysvec_v2);
+	exec_sysvec_init_secondary(&elf64_freebsd_sysvec_v2,
+	    &elf64_freebsd_sysvec_v1);
+	/*
+	 * Adjust elfv2 sigcode after elfv1 sysvec is initialized.
+	 * exec_sysvec_init_secondary() assumes secondary sysvecs use
+	 * identical signal code, and skips allocating a second copy.
+	 * Since the ELFv2 trampoline is a strict subset of the ELFv1 code,
+	 * we can work around this by adjusting the base address. This also
+	 * avoids two copies of the trampoline code being allocated!
+	 */
+	elf64_freebsd_sysvec_v2.sv_sigcode_base +=
+	    (uintptr_t)sigcode64_elfv2 - (uintptr_t)&sigcode64;
+	elf64_freebsd_sysvec_v2.sv_szsigcode = &szsigcode64_elfv2;
+}
+SYSINIT(elf64_sysvec, SI_SUB_EXEC, SI_ORDER_ANY, ppc64_init_sysvecs, NULL);
 
 static boolean_t
 ppc64_elfv1_header_match(struct image_params *params, int32_t *osrel __unused,


More information about the svn-src-all mailing list