commit 1ebc48986ea4624faf1441d29be621cac9ffb6c5 Author: Brandon Bergren Date: Fri Apr 30 18:53:56 2021 -0500 Fix ELFv2 loading for FreeBSD ppc64*. diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index 69448e5eca..99cce12035 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -777,6 +777,8 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, setup_arg_pages(bprm, info, &bprm->p, &bprm->stringp); info->start_stack = bprm->p; + info->elf_flags = elf_ex.e_flags; + error = load_elf_sections(&elf_ex, elf_phdata, bprm->fd, et_dyn_addr, &load_addr); for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { diff --git a/bsd-user/ppc/target_arch_thread.h b/bsd-user/ppc/target_arch_thread.h index 0439d36ecb..f04fde59ef 100644 --- a/bsd-user/ppc/target_arch_thread.h +++ b/bsd-user/ppc/target_arch_thread.h @@ -40,10 +40,24 @@ static inline void target_thread_set_upcall(CPUPPCState *regs, abi_ulong entry, /* r3 = arg */ regs->gpr[3] = arg; /* srr0 = start function entry */ + #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) - get_user_ual(regs->nip, entry); - get_user_ual(regs->gpr[2], entry + sizeof(abi_ulong)); - get_user_ual(regs->gpr[11], entry + 2 * sizeof(abi_ulong)); + + /* Determine what PPC64 ABI we are running under. */ + CPUState *cpu = env_cpu(regs); + TaskState *ts = (TaskState *)cpu->opaque; + struct image_info *infop = ts->info; + + if ((infop->elf_flags & 0x3) < 2) { + /* ELFv1: Initialize TOC and environment from function descriptor. */ + get_user_ual(regs->nip, entry); + get_user_ual(regs->gpr[2], entry + sizeof(abi_ulong)); + get_user_ual(regs->gpr[11], entry + 2 * sizeof(abi_ulong)); + } else { + /* ELFv2: entry point copied to GPR 12. */ + regs->nip = entry; + regs->gpr[12] = entry; + } #else regs->nip = entry; #endif @@ -57,13 +71,20 @@ static inline void target_thread_init(struct target_pt_regs *regs, #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) regs->gpr[1] = -roundup(-stack + 48, 16); - get_user_u64(regs->gpr[2], infop->entry + 8); - regs->gpr[2] += infop->load_addr; - get_user_u64(regs->gpr[11], infop->entry + 16); - regs->gpr[11] += infop->load_addr; - get_user_u64(infop->entry, infop->entry); - infop->entry += infop->load_addr; + /* Handle ELFv1 initialization if needed */ + if ((infop->elf_flags & 0x3) < 2) { + get_user_u64(regs->gpr[2], infop->entry + 8); + regs->gpr[2] += infop->load_addr; + get_user_u64(regs->gpr[11], infop->entry + 16); + regs->gpr[11] += infop->load_addr; + + get_user_u64(infop->entry, infop->entry); + infop->entry += infop->load_addr; + } + else { + regs->gpr[12] = infop->entry; + } #else regs->gpr[1] = -roundup(-stack + 8, 16); #endif diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index e17f034be3..83973fae01 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -84,6 +84,7 @@ struct image_info { abi_ulong data_offset; abi_ulong arg_start; abi_ulong arg_end; + uint32_t elf_flags; }; #define MAX_SIGQUEUE_SIZE 1024