elf32_machdep.c revision 133464
1142215Sglebius/*- 2142215Sglebius * Copyright 1996-1998 John D. Polstra. 3142215Sglebius * All rights reserved. 4142215Sglebius * 5142215Sglebius * Redistribution and use in source and binary forms, with or without 6142215Sglebius * modification, are permitted provided that the following conditions 7142215Sglebius * are met: 8142215Sglebius * 1. Redistributions of source code must retain the above copyright 9142215Sglebius * notice, this list of conditions and the following disclaimer. 10142215Sglebius * 2. Redistributions in binary form must reproduce the above copyright 11142215Sglebius * notice, this list of conditions and the following disclaimer in the 12142215Sglebius * documentation and/or other materials provided with the distribution. 13142215Sglebius * 14142215Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15142215Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16142215Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17142215Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18142215Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19142215Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20142215Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21142215Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22142215Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23142215Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24142215Sglebius * 25142215Sglebius * $FreeBSD: head/sys/powerpc/powerpc/elf_machdep.c 133464 2004-08-11 02:35:06Z marcel $ 26142215Sglebius */ 27142215Sglebius 28142215Sglebius#include <sys/param.h> 29142215Sglebius#include <sys/kernel.h> 30142215Sglebius#include <sys/systm.h> 31142215Sglebius#include <sys/exec.h> 32142215Sglebius#include <sys/imgact.h> 33142215Sglebius#include <sys/malloc.h> 34142215Sglebius#include <sys/proc.h> 35142215Sglebius#include <sys/namei.h> 36142215Sglebius#include <sys/fcntl.h> 37142215Sglebius#include <sys/sysent.h> 38142215Sglebius#include <sys/imgact_elf.h> 39142215Sglebius#include <sys/syscall.h> 40142215Sglebius#include <sys/signalvar.h> 41142215Sglebius#include <sys/vnode.h> 42142215Sglebius#include <sys/linker.h> 43142215Sglebius 44142215Sglebius#include <vm/vm.h> 45142215Sglebius#include <vm/vm_param.h> 46142215Sglebius 47142215Sglebius#include <machine/cpu.h> 48142215Sglebius#include <machine/elf.h> 49142215Sglebius#include <machine/md_var.h> 50142215Sglebius 51142215Sglebiusstruct sysentvec elf32_freebsd_sysvec = { 52142215Sglebius SYS_MAXSYSCALL, 53142215Sglebius sysent, 54142215Sglebius 0, 55142224Sglebius 0, 56142215Sglebius NULL, 57142215Sglebius 0, 58142215Sglebius NULL, 59142215Sglebius NULL, 60142215Sglebius __elfN(freebsd_fixup), 61142215Sglebius sendsig, 62142224Sglebius sigcode, 63142215Sglebius &szsigcode, 64142215Sglebius NULL, 65142215Sglebius "FreeBSD ELF32", 66142215Sglebius __elfN(coredump), 67142215Sglebius NULL, 68142215Sglebius MINSIGSTKSZ, 69142215Sglebius PAGE_SIZE, 70142215Sglebius VM_MIN_ADDRESS, 71142215Sglebius VM_MAXUSER_ADDRESS, 72142215Sglebius USRSTACK, 73142215Sglebius PS_STRINGS, 74142215Sglebius VM_PROT_ALL, 75142215Sglebius exec_copyout_strings, 76142215Sglebius exec_setregs, 77142215Sglebius NULL 78142215Sglebius}; 79142215Sglebius 80142215Sglebiusstatic Elf32_Brandinfo freebsd_brand_info = { 81142215Sglebius ELFOSABI_FREEBSD, 82142215Sglebius EM_PPC, 83142215Sglebius "FreeBSD", 84142215Sglebius NULL, 85142215Sglebius "/libexec/ld-elf.so.1", 86142215Sglebius &elf32_freebsd_sysvec, 87142215Sglebius NULL, 88142215Sglebius }; 89142215Sglebius 90142215SglebiusSYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY, 91142215Sglebius (sysinit_cfunc_t) elf32_insert_brand_entry, 92142215Sglebius &freebsd_brand_info); 93142215Sglebius 94142215Sglebiusstatic Elf32_Brandinfo freebsd_brand_oinfo = { 95142215Sglebius ELFOSABI_FREEBSD, 96142215Sglebius EM_PPC, 97142215Sglebius "FreeBSD", 98142215Sglebius NULL, 99203486Sru "/usr/libexec/ld-elf.so.1", 100142215Sglebius &elf32_freebsd_sysvec, 101142215Sglebius NULL, 102142215Sglebius }; 103142215Sglebius 104142215SglebiusSYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY, 105142215Sglebius (sysinit_cfunc_t) elf32_insert_brand_entry, 106142215Sglebius &freebsd_brand_oinfo); 107142215Sglebius 108142215Sglebius 109142215Sglebiusvoid 110142215Sglebiuself32_dump_thread(struct thread *td __unused, void *dst __unused, 111142215Sglebius size_t *off __unused) 112142215Sglebius{ 113142215Sglebius} 114142215Sglebius 115142215Sglebius 116142215Sglebius/* Process one elf relocation with addend. */ 117142215Sglebiusstatic int 118142215Sglebiuself_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, 119142215Sglebius int type, int local, elf_lookup_fn lookup) 120142215Sglebius{ 121142215Sglebius Elf_Addr *where; 122142215Sglebius Elf_Half *hwhere; 123142215Sglebius Elf_Addr addr; 124142215Sglebius Elf_Addr addend; 125142215Sglebius Elf_Word rtype, symidx; 126142215Sglebius const Elf_Rela *rela; 127142215Sglebius 128142215Sglebius switch (type) { 129142215Sglebius case ELF_RELOC_REL: 130142215Sglebius panic("PPC only supports RELA relocations"); 131142215Sglebius break; 132142215Sglebius case ELF_RELOC_RELA: 133142215Sglebius rela = (const Elf_Rela *)data; 134142215Sglebius where = (Elf_Addr *) (relocbase + rela->r_offset); 135142215Sglebius hwhere = (Elf_Half *) (relocbase + rela->r_offset); 136142215Sglebius addend = rela->r_addend; 137142215Sglebius rtype = ELF_R_TYPE(rela->r_info); 138142215Sglebius symidx = ELF_R_SYM(rela->r_info); 139142215Sglebius break; 140142215Sglebius default: 141142215Sglebius panic("elf_reloc: unknown relocation mode %d\n", type); 142142215Sglebius } 143142215Sglebius 144142215Sglebius switch (rtype) { 145142215Sglebius 146142215Sglebius case R_PPC_NONE: 147142215Sglebius break; 148142215Sglebius 149142215Sglebius case R_PPC_ADDR32: /* word32 S + A */ 150142215Sglebius addr = lookup(lf, symidx, 1); 151142215Sglebius if (addr == 0) 152142215Sglebius return -1; 153142215Sglebius addr += addend; 154142215Sglebius *where = addr; 155142215Sglebius break; 156142215Sglebius 157142215Sglebius case R_PPC_ADDR16_LO: /* #lo(S) */ 158142215Sglebius addr = lookup(lf, symidx, 1); 159142215Sglebius if (addr == 0) 160142215Sglebius return -1; 161142215Sglebius /* 162142215Sglebius * addend values are sometimes relative to sections 163142215Sglebius * (i.e. .rodata) in rela, where in reality they 164142215Sglebius * are relative to relocbase. Detect this condition. 165142215Sglebius */ 166142215Sglebius if (addr > relocbase && addr <= (relocbase + addend)) 167142215Sglebius addr = relocbase + addend; 168142215Sglebius else 169142215Sglebius addr += addend; 170142215Sglebius *hwhere = addr & 0xffff; 171142215Sglebius break; 172142215Sglebius 173142215Sglebius case R_PPC_ADDR16_HA: /* #ha(S) */ 174142215Sglebius addr = lookup(lf, symidx, 1); 175142215Sglebius if (addr == 0) 176142215Sglebius return -1; 177142215Sglebius /* 178142215Sglebius * addend values are sometimes relative to sections 179142215Sglebius * (i.e. .rodata) in rela, where in reality they 180142215Sglebius * are relative to relocbase. Detect this condition. 181142215Sglebius */ 182142215Sglebius if (addr > relocbase && addr <= (relocbase + addend)) 183142215Sglebius addr = relocbase + addend; 184142215Sglebius else 185142215Sglebius addr += addend; 186142215Sglebius *hwhere = ((addr >> 16) + ((addr & 0x8000) ? 1 : 0)) 187142224Sglebius & 0xffff; 188142215Sglebius break; 189142215Sglebius 190142215Sglebius case R_PPC_RELATIVE: /* word32 B + A */ 191142215Sglebius *where = relocbase + addend; 192142215Sglebius break; 193142215Sglebius 194142215Sglebius default: 195142215Sglebius printf("kldload: unexpected relocation type %d\n", 196142215Sglebius (int) rtype); 197142215Sglebius return -1; 198142215Sglebius } 199142215Sglebius return(0); 200142215Sglebius} 201 202int 203elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, 204 elf_lookup_fn lookup) 205{ 206 207 return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup)); 208} 209 210int 211elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, 212 int type, elf_lookup_fn lookup) 213{ 214 215 return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup)); 216} 217 218int 219elf_cpu_load_file(linker_file_t lf) 220{ 221 /* Only sync the cache for non-kernel modules */ 222 if (lf->id != 1) 223 __syncicache(lf->address, lf->size); 224 return (0); 225} 226 227int 228elf_cpu_unload_file(linker_file_t lf __unused) 229{ 230 231 return (0); 232} 233