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.
This commit is contained in:
Nathan Whitehorn 2015-11-23 17:07:51 +00:00
parent c2c58185e5
commit fd6820bbc8
6 changed files with 152 additions and 32 deletions

View File

@ -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; \

View File

@ -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;

View File

@ -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" \

View File

@ -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 Elf64_Brandinfo freebsd_brand_info = {
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,
.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(elf64, SI_SUB_EXEC, SI_ORDER_ANY,
SYSINIT(elf64v1, SI_SUB_EXEC, SI_ORDER_ANY,
(sysinit_cfunc_t) elf64_insert_brand_entry,
&freebsd_brand_info);
&freebsd_brand_info_elfv1);
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_v2,
.interp_newpath = NULL,
.brand_note = &elf64_freebsd_brandnote,
.flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
.header_supported = &ppc64_elfv2_header_match
};
SYSINIT(elf64v2, SI_SUB_EXEC, SI_ORDER_ANY,
(sysinit_cfunc_t) elf64_insert_brand_entry,
&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;

View File

@ -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;

View File

@ -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)