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 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: stable/11/sys/amd64/amd64/elf_machdep.c 338867 2018-09-21 20:40:37Z markj $"); 28 29#include <sys/param.h> 30#include <sys/kernel.h> 31#include <sys/systm.h> 32#include <sys/exec.h> 33#include <sys/imgact.h> 34#include <sys/linker.h> 35#include <sys/proc.h> 36#include <sys/sysent.h> 37#include <sys/imgact_elf.h> 38#include <sys/syscall.h> 39#include <sys/signalvar.h> 40#include <sys/vnode.h> 41 42#include <vm/vm.h> 43#include <vm/pmap.h> 44#include <vm/vm_param.h> 45 46#include <machine/elf.h> 47#include <machine/fpu.h> 48#include <machine/md_var.h> 49 50struct sysentvec elf64_freebsd_sysvec = { 51 .sv_size = SYS_MAXSYSCALL, 52 .sv_table = sysent, 53 .sv_mask = 0, 54 .sv_errsize = 0, 55 .sv_errtbl = NULL, 56 .sv_transtrap = NULL, 57 .sv_fixup = __elfN(freebsd_fixup), 58 .sv_sendsig = sendsig, 59 .sv_sigcode = sigcode, 60 .sv_szsigcode = &szsigcode, 61 .sv_name = "FreeBSD ELF64", 62 .sv_coredump = __elfN(coredump), 63 .sv_imgact_try = NULL, 64 .sv_minsigstksz = MINSIGSTKSZ, 65 .sv_pagesize = PAGE_SIZE, 66 .sv_minuser = VM_MIN_ADDRESS, 67 .sv_maxuser = VM_MAXUSER_ADDRESS, 68 .sv_usrstack = USRSTACK, 69 .sv_psstrings = PS_STRINGS, 70 .sv_stackprot = VM_PROT_ALL, 71 .sv_copyout_strings = exec_copyout_strings, 72 .sv_setregs = exec_setregs, 73 .sv_fixlimit = NULL, 74 .sv_maxssiz = NULL, 75 .sv_flags = SV_ABI_FREEBSD | SV_LP64 | SV_SHP | SV_TIMEKEEP, 76 .sv_set_syscall_retval = cpu_set_syscall_retval, 77 .sv_fetch_syscall_args = cpu_fetch_syscall_args, 78 .sv_syscallnames = syscallnames, 79 .sv_shared_page_base = SHAREDPAGE, 80 .sv_shared_page_len = PAGE_SIZE, 81 .sv_schedtail = NULL, 82 .sv_thread_detach = NULL, 83 .sv_trap = NULL, 84}; 85INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec); 86 87void 88amd64_lower_shared_page(struct sysentvec *sv) 89{ 90 if (hw_lower_amd64_sharedpage != 0) { 91 sv->sv_maxuser -= PAGE_SIZE; 92 sv->sv_shared_page_base -= PAGE_SIZE; 93 sv->sv_usrstack -= PAGE_SIZE; 94 sv->sv_psstrings -= PAGE_SIZE; 95 } 96} 97 98/* 99 * Do this fixup before INIT_SYSENTVEC (SI_ORDER_ANY) because the latter 100 * uses the value of sv_shared_page_base. 101 */ 102SYSINIT(elf64_sysvec_fixup, SI_SUB_EXEC, SI_ORDER_FIRST, 103 (sysinit_cfunc_t) amd64_lower_shared_page, 104 &elf64_freebsd_sysvec); 105 106static Elf64_Brandinfo freebsd_brand_info = { 107 .brand = ELFOSABI_FREEBSD, 108 .machine = EM_X86_64, 109 .compat_3_brand = "FreeBSD", 110 .emul_path = NULL, 111 .interp_path = "/libexec/ld-elf.so.1", 112 .sysvec = &elf64_freebsd_sysvec, 113 .interp_newpath = NULL, 114 .brand_note = &elf64_freebsd_brandnote, 115 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 116}; 117 118SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_FIRST, 119 (sysinit_cfunc_t) elf64_insert_brand_entry, 120 &freebsd_brand_info); 121 122static Elf64_Brandinfo freebsd_brand_oinfo = { 123 .brand = ELFOSABI_FREEBSD, 124 .machine = EM_X86_64, 125 .compat_3_brand = "FreeBSD", 126 .emul_path = NULL, 127 .interp_path = "/usr/libexec/ld-elf.so.1", 128 .sysvec = &elf64_freebsd_sysvec, 129 .interp_newpath = NULL, 130 .brand_note = &elf64_freebsd_brandnote, 131 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 132}; 133 134SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY, 135 (sysinit_cfunc_t) elf64_insert_brand_entry, 136 &freebsd_brand_oinfo); 137 138static Elf64_Brandinfo kfreebsd_brand_info = { 139 .brand = ELFOSABI_FREEBSD, 140 .machine = EM_X86_64, 141 .compat_3_brand = "FreeBSD", 142 .emul_path = NULL, 143 .interp_path = "/lib/ld-kfreebsd-x86-64.so.1", 144 .sysvec = &elf64_freebsd_sysvec, 145 .interp_newpath = NULL, 146 .brand_note = &elf64_kfreebsd_brandnote, 147 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE_MANDATORY 148}; 149 150SYSINIT(kelf64, SI_SUB_EXEC, SI_ORDER_ANY, 151 (sysinit_cfunc_t) elf64_insert_brand_entry, 152 &kfreebsd_brand_info); 153 154void 155elf64_dump_thread(struct thread *td, void *dst, size_t *off) 156{ 157 void *buf; 158 size_t len; 159 160 len = 0; 161 if (use_xsave) { 162 if (dst != NULL) { 163 fpugetregs(td); 164 len += elf64_populate_note(NT_X86_XSTATE, 165 get_pcb_user_save_td(td), dst, 166 cpu_max_ext_state_size, &buf); 167 *(uint64_t *)((char *)buf + X86_XSTATE_XCR0_OFFSET) = 168 xsave_mask; 169 } else 170 len += elf64_populate_note(NT_X86_XSTATE, NULL, NULL, 171 cpu_max_ext_state_size, NULL); 172 } 173 *off = len; 174} 175 176bool 177elf_is_ifunc_reloc(Elf_Size r_info) 178{ 179 180 return (ELF_R_TYPE(r_info) == R_X86_64_IRELATIVE); 181} 182 183/* Process one elf relocation with addend. */ 184static int 185elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, 186 int type, elf_lookup_fn lookup) 187{ 188 Elf64_Addr *where, val; 189 Elf32_Addr *where32, val32; 190 Elf_Addr addr; 191 Elf_Addr addend; 192 Elf_Size rtype, symidx; 193 const Elf_Rel *rel; 194 const Elf_Rela *rela; 195 int error; 196 197 switch (type) { 198 case ELF_RELOC_REL: 199 rel = (const Elf_Rel *)data; 200 where = (Elf_Addr *) (relocbase + rel->r_offset); 201 rtype = ELF_R_TYPE(rel->r_info); 202 symidx = ELF_R_SYM(rel->r_info); 203 /* Addend is 32 bit on 32 bit relocs */ 204 switch (rtype) { 205 case R_X86_64_PC32: 206 case R_X86_64_32S: 207 case R_X86_64_PLT32: 208 addend = *(Elf32_Addr *)where; 209 break; 210 default: 211 addend = *where; 212 break; 213 } 214 break; 215 case ELF_RELOC_RELA: 216 rela = (const Elf_Rela *)data; 217 where = (Elf_Addr *) (relocbase + rela->r_offset); 218 addend = rela->r_addend; 219 rtype = ELF_R_TYPE(rela->r_info); 220 symidx = ELF_R_SYM(rela->r_info); 221 break; 222 default: 223 panic("unknown reloc type %d\n", type); 224 } 225 226 switch (rtype) { 227 case R_X86_64_NONE: /* none */ 228 break; 229 230 case R_X86_64_64: /* S + A */ 231 error = lookup(lf, symidx, 1, &addr); 232 val = addr + addend; 233 if (error != 0) 234 return -1; 235 if (*where != val) 236 *where = val; 237 break; 238 239 case R_X86_64_PC32: /* S + A - P */ 240 case R_X86_64_PLT32: /* L + A - P, L is PLT location for 241 the symbol, which we treat as S */ 242 error = lookup(lf, symidx, 1, &addr); 243 where32 = (Elf32_Addr *)where; 244 val32 = (Elf32_Addr)(addr + addend - (Elf_Addr)where); 245 if (error != 0) 246 return -1; 247 if (*where32 != val32) 248 *where32 = val32; 249 break; 250 251 case R_X86_64_32S: /* S + A sign extend */ 252 error = lookup(lf, symidx, 1, &addr); 253 val32 = (Elf32_Addr)(addr + addend); 254 where32 = (Elf32_Addr *)where; 255 if (error != 0) 256 return -1; 257 if (*where32 != val32) 258 *where32 = val32; 259 break; 260 261 case R_X86_64_COPY: /* none */ 262 /* 263 * There shouldn't be copy relocations in kernel 264 * objects. 265 */ 266 printf("kldload: unexpected R_COPY relocation\n"); 267 return (-1); 268 break; 269 270 case R_X86_64_GLOB_DAT: /* S */ 271 case R_X86_64_JMP_SLOT: /* XXX need addend + offset */ 272 error = lookup(lf, symidx, 1, &addr); 273 if (error != 0) 274 return -1; 275 if (*where != addr) 276 *where = addr; 277 break; 278 279 case R_X86_64_RELATIVE: /* B + A */ 280 addr = relocbase + addend; 281 val = addr; 282 if (*where != val) 283 *where = val; 284 break; 285 286 case R_X86_64_IRELATIVE: 287 addr = relocbase + addend; 288 val = ((Elf64_Addr (*)(void))addr)(); 289 if (*where != val) 290 *where = val; 291 break; 292 293 default: 294 printf("kldload: unexpected relocation type %ld\n", 295 rtype); 296 return (-1); 297 } 298 return (0); 299} 300 301int 302elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, 303 elf_lookup_fn lookup) 304{ 305 306 return (elf_reloc_internal(lf, relocbase, data, type, lookup)); 307} 308 309int 310elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, 311 int type, elf_lookup_fn lookup) 312{ 313 314 return (elf_reloc_internal(lf, relocbase, data, type, lookup)); 315} 316 317int 318elf_cpu_load_file(linker_file_t lf __unused) 319{ 320 321 return (0); 322} 323 324int 325elf_cpu_unload_file(linker_file_t lf __unused) 326{ 327 328 return (0); 329} 330