elf_machdep.c revision 288287
1/*- 2 * Copyright 1996-1998 John D. Polstra. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * $FreeBSD: stable/10/sys/ia64/ia64/elf_machdep.c 288287 2015-09-27 01:33:43Z kib $ 26 */ 27 28#include <sys/param.h> 29#include <sys/kernel.h> 30#include <sys/systm.h> 31#include <sys/exec.h> 32#include <sys/imgact.h> 33#include <sys/malloc.h> 34#include <sys/proc.h> 35#include <sys/namei.h> 36#include <sys/fcntl.h> 37#include <sys/vnode.h> 38#include <sys/linker.h> 39#include <sys/sysent.h> 40#include <sys/imgact_elf.h> 41#include <sys/syscall.h> 42#include <sys/signalvar.h> 43 44#include <vm/vm.h> 45#include <vm/vm_param.h> 46 47#include <machine/elf.h> 48#include <machine/frame.h> 49#include <machine/md_var.h> 50#include <machine/unwind.h> 51 52Elf_Addr link_elf_get_gp(linker_file_t); 53 54extern Elf_Addr fptr_storage[]; 55 56struct sysentvec elf64_freebsd_sysvec = { 57 .sv_size = SYS_MAXSYSCALL, 58 .sv_table = sysent, 59 .sv_mask = 0, 60 .sv_sigsize = 0, 61 .sv_sigtbl = NULL, 62 .sv_errsize = 0, 63 .sv_errtbl = NULL, 64 .sv_transtrap = NULL, 65 .sv_fixup = __elfN(freebsd_fixup), 66 .sv_sendsig = sendsig, 67 .sv_sigcode = NULL, 68 .sv_szsigcode = NULL, 69 .sv_prepsyscall = NULL, 70 .sv_name = "FreeBSD ELF64", 71 .sv_coredump = __elfN(coredump), 72 .sv_imgact_try = NULL, 73 .sv_minsigstksz = MINSIGSTKSZ, 74 .sv_pagesize = PAGE_SIZE, 75 .sv_minuser = VM_MIN_ADDRESS, 76 .sv_maxuser = VM_MAXUSER_ADDRESS, 77 .sv_usrstack = USRSTACK, 78 .sv_psstrings = PS_STRINGS, 79 .sv_stackprot = VM_PROT_READ|VM_PROT_WRITE, 80 .sv_copyout_strings = exec_copyout_strings, 81 .sv_setregs = exec_setregs, 82 .sv_fixlimit = NULL, 83 .sv_maxssiz = NULL, 84 .sv_flags = SV_ABI_FREEBSD | SV_LP64, 85 .sv_set_syscall_retval = cpu_set_syscall_retval, 86 .sv_fetch_syscall_args = cpu_fetch_syscall_args, 87 .sv_syscallnames = syscallnames, 88 .sv_schedtail = NULL, 89}; 90 91static Elf64_Brandinfo freebsd_brand_info = { 92 .brand = ELFOSABI_FREEBSD, 93 .machine = EM_IA_64, 94 .compat_3_brand = "FreeBSD", 95 .emul_path = NULL, 96 .interp_path = "/libexec/ld-elf.so.1", 97 .sysvec = &elf64_freebsd_sysvec, 98 .interp_newpath = NULL, 99 .brand_note = &elf64_freebsd_brandnote, 100 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 101}; 102SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_FIRST, 103 (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_info); 104 105static Elf64_Brandinfo freebsd_brand_oinfo = { 106 .brand = ELFOSABI_FREEBSD, 107 .machine = EM_IA_64, 108 .compat_3_brand = "FreeBSD", 109 .emul_path = NULL, 110 .interp_path = "/usr/libexec/ld-elf.so.1", 111 .sysvec = &elf64_freebsd_sysvec, 112 .interp_newpath = NULL, 113 .brand_note = &elf64_freebsd_brandnote, 114 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 115}; 116SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY, 117 (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_oinfo); 118 119 120void 121elf64_dump_thread(struct thread *td, void *dst, size_t *off __unused) 122{ 123 124 /* Flush the dirty registers onto the backingstore. */ 125 if (dst == NULL) 126 ia64_flush_dirty(td, &td->td_frame->tf_special); 127} 128 129 130static int 131lookup_fdesc(linker_file_t lf, Elf_Size symidx, elf_lookup_fn lookup, 132 Elf_Addr *addr1) 133{ 134 linker_file_t top; 135 Elf_Addr addr; 136 const char *symname; 137 int i, error; 138 static int eot = 0; 139 140 error = lookup(lf, symidx, 0, &addr); 141 if (error != 0) { 142 top = lf; 143 symname = elf_get_symname(top, symidx); 144 for (i = 0; i < top->ndeps; i++) { 145 lf = top->deps[i]; 146 addr = (Elf_Addr)linker_file_lookup_symbol(lf, 147 symname, 0); 148 if (addr != 0) 149 break; 150 } 151 if (addr == 0) 152 return (EINVAL); 153 } 154 155 if (eot) 156 return (EINVAL); 157 158 /* 159 * Lookup and/or construct OPD 160 */ 161 for (i = 0; i < 8192; i += 2) { 162 if (fptr_storage[i] == addr) { 163 *addr1 = (Elf_Addr)(fptr_storage + i); 164 return (0); 165 } 166 167 if (fptr_storage[i] == 0) { 168 fptr_storage[i] = addr; 169 fptr_storage[i+1] = link_elf_get_gp(lf); 170 *addr1 = (Elf_Addr)(fptr_storage + i); 171 return (0); 172 } 173 } 174 175 printf("%s: fptr table full\n", __func__); 176 eot = 1; 177 178 return (EINVAL); 179} 180 181/* Process one elf relocation with addend. */ 182static int 183elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, 184 int type, int local, elf_lookup_fn lookup) 185{ 186 Elf_Addr *where; 187 Elf_Addr addend, addr; 188 Elf_Size rtype, symidx; 189 const Elf_Rel *rel; 190 const Elf_Rela *rela; 191 int error; 192 193 switch (type) { 194 case ELF_RELOC_REL: 195 rel = (const Elf_Rel *)data; 196 where = (Elf_Addr *)(relocbase + rel->r_offset); 197 rtype = ELF_R_TYPE(rel->r_info); 198 symidx = ELF_R_SYM(rel->r_info); 199 switch (rtype) { 200 case R_IA_64_DIR64LSB: 201 case R_IA_64_FPTR64LSB: 202 case R_IA_64_REL64LSB: 203 addend = *where; 204 break; 205 default: 206 addend = 0; 207 break; 208 } 209 break; 210 case ELF_RELOC_RELA: 211 rela = (const Elf_Rela *)data; 212 where = (Elf_Addr *)(relocbase + rela->r_offset); 213 rtype = ELF_R_TYPE(rela->r_info); 214 symidx = ELF_R_SYM(rela->r_info); 215 addend = rela->r_addend; 216 break; 217 default: 218 panic("%s: invalid ELF relocation (0x%x)\n", __func__, type); 219 } 220 221 if (local) { 222 if (rtype == R_IA_64_REL64LSB) 223 *where = elf_relocaddr(lf, relocbase + addend); 224 return (0); 225 } 226 227 switch (rtype) { 228 case R_IA_64_NONE: 229 break; 230 case R_IA_64_DIR64LSB: /* word64 LSB S + A */ 231 error = lookup(lf, symidx, 1, &addr); 232 if (error != 0) 233 return (-1); 234 *where = addr + addend; 235 break; 236 case R_IA_64_FPTR64LSB: /* word64 LSB @fptr(S + A) */ 237 if (addend != 0) { 238 printf("%s: addend ignored for OPD relocation\n", 239 __func__); 240 } 241 error = lookup_fdesc(lf, symidx, lookup, &addr); 242 if (error != 0) 243 return (-1); 244 *where = addr; 245 break; 246 case R_IA_64_REL64LSB: /* word64 LSB BD + A */ 247 break; 248 case R_IA_64_IPLTLSB: 249 error = lookup_fdesc(lf, symidx, lookup, &addr); 250 if (error != 0) 251 return (-1); 252 where[0] = *((Elf_Addr*)addr) + addend; 253 where[1] = *((Elf_Addr*)addr + 1); 254 break; 255 default: 256 printf("%s: unknown relocation (0x%x)\n", __func__, 257 (int)rtype); 258 return -1; 259 } 260 261 return (0); 262} 263 264int 265elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, 266 elf_lookup_fn lookup) 267{ 268 269 return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup)); 270} 271 272int 273elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, 274 int type, elf_lookup_fn lookup) 275{ 276 277 return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup)); 278} 279 280int 281elf_cpu_load_file(linker_file_t lf) 282{ 283 Elf_Ehdr *hdr; 284 Elf_Phdr *ph, *phlim; 285 Elf_Addr reloc, vaddr; 286 287 hdr = (Elf_Ehdr *)(lf->address); 288 if (!IS_ELF(*hdr)) { 289 printf("Missing or corrupted ELF header at %p\n", hdr); 290 return (EFTYPE); 291 } 292 293 /* 294 * Iterate over the segments and register the unwind table if 295 * we come across it. 296 */ 297 ph = (Elf_Phdr *)(lf->address + hdr->e_phoff); 298 phlim = ph + hdr->e_phnum; 299 reloc = ~0ULL; 300 while (ph < phlim) { 301 if (ph->p_type == PT_LOAD && reloc == ~0ULL) 302 reloc = (Elf_Addr)lf->address - ph->p_vaddr; 303 304 if (ph->p_type == PT_IA_64_UNWIND) { 305 vaddr = ph->p_vaddr + reloc; 306 unw_table_add((vm_offset_t)lf->address, vaddr, 307 vaddr + ph->p_memsz); 308 } 309 ++ph; 310 } 311 312 /* 313 * Make the I-cache coherent, but don't worry obout the kernel 314 * itself because the loader needs to do that. 315 */ 316 if (lf->id != 1) 317 ia64_sync_icache((uintptr_t)lf->address, lf->size); 318 319 return (0); 320} 321 322int 323elf_cpu_unload_file(linker_file_t lf) 324{ 325 326 unw_table_remove((vm_offset_t)lf->address); 327 return (0); 328} 329