summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2015-11-23 17:07:51 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2015-11-23 17:07:51 +0000
commit114e179345185f1dcad9eb27cb3cd638af89f1be (patch)
tree3e326e81b7ca261f6dba201b10ffbc07010904c0 /sys
parenta77fc20235c4ecd2f8fb8ecacb81edf8ca596bcb (diff)
downloadFreeBSD-src-114e179345185f1dcad9eb27cb3cd638af89f1be.zip
FreeBSD-src-114e179345185f1dcad9eb27cb3cd638af89f1be.tar.gz
Provide support for userland binaries using the new ELFv2 ABI. This is a
new, simplified, ELF ABI that avoids some of the stranger aspects of the existing 64-bit PowerPC ABI (function descriptors, in particular). Actually generating such executables requires a new version of binutils and a newer compiler (either GCC or clang) than GCC 4.2.1.
Diffstat (limited to 'sys')
-rw-r--r--sys/powerpc/include/asm.h2
-rw-r--r--sys/powerpc/include/md_var.h4
-rw-r--r--sys/powerpc/include/profile.h19
-rw-r--r--sys/powerpc/powerpc/elf64_machdep.c130
-rw-r--r--sys/powerpc/powerpc/exec_machdep.c18
-rw-r--r--sys/powerpc/powerpc/sigcode64.S11
6 files changed, 152 insertions, 32 deletions
diff --git a/sys/powerpc/include/asm.h b/sys/powerpc/include/asm.h
index c04cbc2..e5ec398 100644
--- a/sys/powerpc/include/asm.h
+++ b/sys/powerpc/include/asm.h
@@ -85,7 +85,9 @@
.section ".toc","aw"; \
TOC_REF(name): \
.tc name[TC],name
+#endif
+#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1)
#define _ENTRY(name) \
.section ".text"; \
.p2align 2; \
diff --git a/sys/powerpc/include/md_var.h b/sys/powerpc/include/md_var.h
index a90967a..f9d4ef1 100644
--- a/sys/powerpc/include/md_var.h
+++ b/sys/powerpc/include/md_var.h
@@ -37,8 +37,8 @@ extern char sigcode32[];
extern int szsigcode32;
#ifdef __powerpc64__
-extern char sigcode64[];
-extern int szsigcode64;
+extern char sigcode64[], sigcode64_elfv2[];
+extern int szsigcode64, szsigcode64_elfv2;
#endif
extern long Maxmem;
diff --git a/sys/powerpc/include/profile.h b/sys/powerpc/include/profile.h
index eb11fc9..b1481a7 100644
--- a/sys/powerpc/include/profile.h
+++ b/sys/powerpc/include/profile.h
@@ -75,9 +75,10 @@ typedef __ptrdiff_t fptrdiff_t;
* to be restored to what it was on entry to the profiled routine.
*/
-#ifdef __powerpc64__
-#define MCOUNT \
-__asm( " .text \n" \
+#if defined(__powerpc64__)
+
+#if !defined(_CALL_ELF) || _CALL_ELF == 1
+#define MCOUNT_PREAMBLE \
" .align 2 \n" \
" .globl _mcount \n" \
" .section \".opd\",\"aw\" \n" \
@@ -88,7 +89,17 @@ __asm( " .text \n" \
" .size _mcount,24 \n" \
" .type _mcount,@function \n" \
" .align 4 \n" \
- ".L._mcount: \n" \
+ ".L._mcount: \n"
+#else
+#define MCOUNT_PREAMBLE \
+ " .globl _mcount \n" \
+ " .type _mcount,@function \n" \
+ " .align 4 \n" \
+ "_mcount: \n"
+#endif
+
+#define MCOUNT \
+__asm( MCOUNT_PREAMBLE \
" stdu %r1,-(288+128)(%r1) \n" \
" std %r3,48(%r1) \n" \
" std %r4,56(%r1) \n" \
diff --git a/sys/powerpc/powerpc/elf64_machdep.c b/sys/powerpc/powerpc/elf64_machdep.c
index e311d0b..71a9a70 100644
--- a/sys/powerpc/powerpc/elf64_machdep.c
+++ b/sys/powerpc/powerpc/elf64_machdep.c
@@ -49,7 +49,10 @@
#include <machine/elf.h>
#include <machine/md_var.h>
-struct sysentvec elf64_freebsd_sysvec = {
+static void exec_setregs_funcdesc(struct thread *td, struct image_params *imgp,
+ u_long stack);
+
+struct sysentvec elf64_freebsd_sysvec_v1 = {
.sv_size = SYS_MAXSYSCALL,
.sv_table = sysent,
.sv_mask = 0,
@@ -74,6 +77,45 @@ struct sysentvec elf64_freebsd_sysvec = {
.sv_psstrings = PS_STRINGS,
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_strings = exec_copyout_strings,
+ .sv_setregs = exec_setregs_funcdesc,
+ .sv_fixlimit = NULL,
+ .sv_maxssiz = NULL,
+ .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_SHP,
+ .sv_set_syscall_retval = cpu_set_syscall_retval,
+ .sv_fetch_syscall_args = cpu_fetch_syscall_args,
+ .sv_syscallnames = syscallnames,
+ .sv_shared_page_base = SHAREDPAGE,
+ .sv_shared_page_len = PAGE_SIZE,
+ .sv_schedtail = NULL,
+ .sv_thread_detach = NULL,
+};
+INIT_SYSENTVEC(elf64_sysvec_v1, &elf64_freebsd_sysvec_v1);
+
+struct sysentvec elf64_freebsd_sysvec_v2 = {
+ .sv_size = SYS_MAXSYSCALL,
+ .sv_table = sysent,
+ .sv_mask = 0,
+ .sv_sigsize = 0,
+ .sv_sigtbl = NULL,
+ .sv_errsize = 0,
+ .sv_errtbl = NULL,
+ .sv_transtrap = NULL,
+ .sv_fixup = __elfN(freebsd_fixup),
+ .sv_sendsig = sendsig,
+ .sv_sigcode = sigcode64_elfv2,
+ .sv_szsigcode = &szsigcode64_elfv2,
+ .sv_prepsyscall = NULL,
+ .sv_name = "FreeBSD ELF64 V2",
+ .sv_coredump = __elfN(coredump),
+ .sv_imgact_try = NULL,
+ .sv_minsigstksz = MINSIGSTKSZ,
+ .sv_pagesize = PAGE_SIZE,
+ .sv_minuser = VM_MIN_ADDRESS,
+ .sv_maxuser = VM_MAXUSER_ADDRESS,
+ .sv_usrstack = USRSTACK,
+ .sv_psstrings = PS_STRINGS,
+ .sv_stackprot = VM_PROT_ALL,
+ .sv_copyout_strings = exec_copyout_strings,
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
@@ -86,23 +128,44 @@ struct sysentvec elf64_freebsd_sysvec = {
.sv_schedtail = NULL,
.sv_thread_detach = NULL,
};
-INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);
+INIT_SYSENTVEC(elf64_sysvec_v2, &elf64_freebsd_sysvec_v2);
+
+static boolean_t ppc64_elfv1_header_match(struct image_params *params);
+static boolean_t ppc64_elfv2_header_match(struct image_params *params);
+
+static Elf64_Brandinfo freebsd_brand_info_elfv1 = {
+ .brand = ELFOSABI_FREEBSD,
+ .machine = EM_PPC64,
+ .compat_3_brand = "FreeBSD",
+ .emul_path = NULL,
+ .interp_path = "/libexec/ld-elf.so.1",
+ .sysvec = &elf64_freebsd_sysvec_v1,
+ .interp_newpath = NULL,
+ .brand_note = &elf64_freebsd_brandnote,
+ .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
+ .header_supported = &ppc64_elfv1_header_match
+};
+
+SYSINIT(elf64v1, SI_SUB_EXEC, SI_ORDER_ANY,
+ (sysinit_cfunc_t) elf64_insert_brand_entry,
+ &freebsd_brand_info_elfv1);
-static Elf64_Brandinfo freebsd_brand_info = {
+static Elf64_Brandinfo freebsd_brand_info_elfv2 = {
.brand = ELFOSABI_FREEBSD,
.machine = EM_PPC64,
.compat_3_brand = "FreeBSD",
.emul_path = NULL,
.interp_path = "/libexec/ld-elf.so.1",
- .sysvec = &elf64_freebsd_sysvec,
+ .sysvec = &elf64_freebsd_sysvec_v2,
.interp_newpath = NULL,
.brand_note = &elf64_freebsd_brandnote,
- .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
+ .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
+ .header_supported = &ppc64_elfv2_header_match
};
-SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY,
+SYSINIT(elf64v2, SI_SUB_EXEC, SI_ORDER_ANY,
(sysinit_cfunc_t) elf64_insert_brand_entry,
- &freebsd_brand_info);
+ &freebsd_brand_info_elfv2);
static Elf64_Brandinfo freebsd_brand_oinfo = {
.brand = ELFOSABI_FREEBSD,
@@ -110,10 +173,11 @@ static Elf64_Brandinfo freebsd_brand_oinfo = {
.compat_3_brand = "FreeBSD",
.emul_path = NULL,
.interp_path = "/usr/libexec/ld-elf.so.1",
- .sysvec = &elf64_freebsd_sysvec,
+ .sysvec = &elf64_freebsd_sysvec_v1,
.interp_newpath = NULL,
.brand_note = &elf64_freebsd_brandnote,
- .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE
+ .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
+ .header_supported = &ppc64_elfv1_header_match
};
SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
@@ -122,6 +186,50 @@ SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
void elf_reloc_self(Elf_Dyn *dynp, Elf_Addr relocbase);
+static boolean_t
+ppc64_elfv1_header_match(struct image_params *params)
+{
+ const Elf64_Ehdr *hdr = (const Elf64_Ehdr *)params->image_header;
+ int abi = (hdr->e_flags & 3);
+
+ return (abi == 0 || abi == 1);
+}
+
+static boolean_t
+ppc64_elfv2_header_match(struct image_params *params)
+{
+ const Elf64_Ehdr *hdr = (const Elf64_Ehdr *)params->image_header;
+ int abi = (hdr->e_flags & 3);
+
+ return (abi == 2);
+}
+
+static void
+exec_setregs_funcdesc(struct thread *td, struct image_params *imgp,
+ u_long stack)
+{
+ struct trapframe *tf;
+ register_t entry_desc[3];
+
+ tf = trapframe(td);
+ exec_setregs(td, imgp, stack);
+
+ /*
+ * For 64-bit ELFv1, we need to disentangle the function
+ * descriptor
+ *
+ * 0. entry point
+ * 1. TOC value (r2)
+ * 2. Environment pointer (r11)
+ */
+
+ (void)copyin((void *)imgp->entry_addr, entry_desc,
+ sizeof(entry_desc));
+ tf->srr0 = entry_desc[0] + imgp->reloc_base;
+ tf->fixreg[2] = entry_desc[1] + imgp->reloc_base;
+ tf->fixreg[11] = entry_desc[2] + imgp->reloc_base;
+}
+
void
elf64_dump_thread(struct thread *td, void *dst, size_t *off)
{
@@ -190,7 +298,11 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
case R_PPC_JMP_SLOT: /* function descriptor copy */
lookup(lf, symidx, 1, &addr);
+#if !defined(_CALL_ELF) || _CALL_ELF == 1
memcpy(where, (Elf_Addr *)addr, 3*sizeof(Elf_Addr));
+#else
+ memcpy(where, (Elf_Addr *)addr, sizeof(Elf_Addr));
+#endif
__asm __volatile("dcbst 0,%0; sync" :: "r"(where) : "memory");
break;
diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c
index 0019faa..88bbf7cb 100644
--- a/sys/powerpc/powerpc/exec_machdep.c
+++ b/sys/powerpc/powerpc/exec_machdep.c
@@ -501,9 +501,6 @@ exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
{
struct trapframe *tf;
register_t argc;
- #ifdef __powerpc64__
- register_t entry_desc[3];
- #endif
tf = trapframe(td);
bzero(tf, sizeof *tf);
@@ -546,24 +543,13 @@ exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
tf->fixreg[7] = 0; /* termination vector */
tf->fixreg[8] = (register_t)imgp->ps_strings; /* NetBSD extension */
+ tf->srr0 = imgp->entry_addr;
#ifdef __powerpc64__
- /*
- * For 64-bit, we need to disentangle the function descriptor
- *
- * 0. entry point
- * 1. TOC value (r2)
- * 2. Environment pointer (r11)
- */
-
- (void)copyin((void *)imgp->entry_addr, entry_desc, sizeof(entry_desc));
- tf->srr0 = entry_desc[0] + imgp->reloc_base;
- tf->fixreg[2] = entry_desc[1] + imgp->reloc_base;
- tf->fixreg[11] = entry_desc[2] + imgp->reloc_base;
+ tf->fixreg[12] = imgp->entry_addr;
tf->srr1 = PSL_SF | PSL_USERSET | PSL_FE_DFLT;
if (mfmsr() & PSL_HV)
tf->srr1 |= PSL_HV;
#else
- tf->srr0 = imgp->entry_addr;
tf->srr1 = PSL_USERSET | PSL_FE_DFLT;
#endif
td->td_pcb->pcb_flags = 0;
diff --git a/sys/powerpc/powerpc/sigcode64.S b/sys/powerpc/powerpc/sigcode64.S
index ec8e2b2..47be3ab 100644
--- a/sys/powerpc/powerpc/sigcode64.S
+++ b/sys/powerpc/powerpc/sigcode64.S
@@ -42,15 +42,21 @@
*
* On entry r1 points to a struct sigframe at bottom of current stack.
* All other registers are unchanged.
+ *
+ * Entered midway through for v2 ELF binaries that don't need to deal with
+ * function descriptors.
+ *
*/
.globl CNAME(sigcode64),CNAME(szsigcode64)
+ .globl CNAME(sigcode64_elfv2),CNAME(szsigcode64_elfv2)
CNAME(sigcode64):
- addi 1,1,-112 /* reserved space for callee */
mflr 2 /* resolve function descriptor */
ld 0,0(2)
ld 2,8(2)
mtlr 0
+CNAME(sigcode64_elfv2):
+ addi 1,1,-112 /* reserved space for callee */
blrl
addi 3,1,112+SF_UC /* restore sp, and get &frame->sf_uc */
@@ -64,3 +70,6 @@ endsigcode64:
.data
CNAME(szsigcode64):
.long endsigcode64 - CNAME(sigcode64)
+CNAME(szsigcode64_elfv2):
+ .long endsigcode64 - CNAME(sigcode64_elfv2)
+
OpenPOWER on IntegriCloud