1033f58dfSPeter Wemm /*- 2c49761ddSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3c49761ddSPedro F. Giffuni * 4033f58dfSPeter Wemm * Copyright 1996-1998 John D. Polstra. 5033f58dfSPeter Wemm * All rights reserved. 6033f58dfSPeter Wemm * 7033f58dfSPeter Wemm * Redistribution and use in source and binary forms, with or without 8033f58dfSPeter Wemm * modification, are permitted provided that the following conditions 9033f58dfSPeter Wemm * are met: 10033f58dfSPeter Wemm * 1. Redistributions of source code must retain the above copyright 11033f58dfSPeter Wemm * notice, this list of conditions and the following disclaimer. 12033f58dfSPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 13033f58dfSPeter Wemm * notice, this list of conditions and the following disclaimer in the 14033f58dfSPeter Wemm * documentation and/or other materials provided with the distribution. 15033f58dfSPeter Wemm * 16033f58dfSPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17033f58dfSPeter Wemm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18033f58dfSPeter Wemm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19033f58dfSPeter Wemm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20033f58dfSPeter Wemm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21033f58dfSPeter Wemm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22033f58dfSPeter Wemm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23033f58dfSPeter Wemm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24033f58dfSPeter Wemm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25033f58dfSPeter Wemm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26033f58dfSPeter Wemm */ 27033f58dfSPeter Wemm 2856ae44c5SDavid E. O'Brien #include <sys/cdefs.h> 2956ae44c5SDavid E. O'Brien __FBSDID("$FreeBSD$"); 3056ae44c5SDavid E. O'Brien 31033f58dfSPeter Wemm #include <sys/param.h> 323ebc1248SPeter Wemm #include <sys/kernel.h> 33033f58dfSPeter Wemm #include <sys/systm.h> 34f36ba452SJake Burkholder #include <sys/exec.h> 35f36ba452SJake Burkholder #include <sys/imgact.h> 36033f58dfSPeter Wemm #include <sys/linker.h> 37afe1a688SKonstantin Belousov #include <sys/proc.h> 38548a2ec4SAndrew Turner #include <sys/reg.h> 393ebc1248SPeter Wemm #include <sys/sysent.h> 403ebc1248SPeter Wemm #include <sys/imgact_elf.h> 413ebc1248SPeter Wemm #include <sys/syscall.h> 423ebc1248SPeter Wemm #include <sys/signalvar.h> 433ebc1248SPeter Wemm #include <sys/vnode.h> 44f36ba452SJake Burkholder 45f36ba452SJake Burkholder #include <vm/vm.h> 46f36ba452SJake Burkholder #include <vm/pmap.h> 47f36ba452SJake Burkholder #include <vm/vm_param.h> 48f36ba452SJake Burkholder 49033f58dfSPeter Wemm #include <machine/elf.h> 50180e57e5SJohn Baldwin #include <machine/fpu.h> 513ebc1248SPeter Wemm #include <machine/md_var.h> 523ebc1248SPeter Wemm 53ab4524b3SKonstantin Belousov #include "vdso_offsets.h" 54ab4524b3SKonstantin Belousov 55ab4524b3SKonstantin Belousov extern const char _binary_elf_vdso_so_1_start[]; 56ab4524b3SKonstantin Belousov extern const char _binary_elf_vdso_so_1_end[]; 57ab4524b3SKonstantin Belousov extern char _binary_elf_vdso_so_1_size; 58ab4524b3SKonstantin Belousov 599ce875d9SKonstantin Belousov struct sysentvec elf64_freebsd_sysvec_la48 = { 60a8d403e1SKonstantin Belousov .sv_size = SYS_MAXSYSCALL, 61a8d403e1SKonstantin Belousov .sv_table = sysent, 62a8d403e1SKonstantin Belousov .sv_fixup = __elfN(freebsd_fixup), 63a8d403e1SKonstantin Belousov .sv_sendsig = sendsig, 64ab4524b3SKonstantin Belousov .sv_sigcode = _binary_elf_vdso_so_1_start, 65ab4524b3SKonstantin Belousov .sv_szsigcode = (int *)&_binary_elf_vdso_so_1_size, 66ab4524b3SKonstantin Belousov .sv_sigcodeoff = VDSO_SIGCODE_OFFSET, 67a8d403e1SKonstantin Belousov .sv_name = "FreeBSD ELF64", 68a8d403e1SKonstantin Belousov .sv_coredump = __elfN(coredump), 69435754a5SEdward Tomasz Napierala .sv_elf_core_osabi = ELFOSABI_FREEBSD, 70435754a5SEdward Tomasz Napierala .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR, 71435754a5SEdward Tomasz Napierala .sv_elf_core_prepare_notes = __elfN(prepare_notes), 72a8d403e1SKonstantin Belousov .sv_imgact_try = NULL, 73a8d403e1SKonstantin Belousov .sv_minsigstksz = MINSIGSTKSZ, 74a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 759ce875d9SKonstantin Belousov .sv_maxuser = VM_MAXUSER_ADDRESS_LA48, 769ce875d9SKonstantin Belousov .sv_usrstack = USRSTACK_LA48, 779ce875d9SKonstantin Belousov .sv_psstrings = PS_STRINGS_LA48, 783fc21fddSMark Johnston .sv_psstringssz = sizeof(struct ps_strings), 79a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 80e3532331SJohn Baldwin .sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs), 81a8d403e1SKonstantin Belousov .sv_copyout_strings = exec_copyout_strings, 82a8d403e1SKonstantin Belousov .sv_setregs = exec_setregs, 83a8d403e1SKonstantin Belousov .sv_fixlimit = NULL, 84b4cf0e62SKonstantin Belousov .sv_maxssiz = NULL, 85fa50a355SKonstantin Belousov .sv_flags = SV_ABI_FREEBSD | SV_ASLR | SV_LP64 | SV_SHP | 86ab4524b3SKonstantin Belousov SV_TIMEKEEP | SV_RNG_SEED_VER | SV_DSO_SIG, 87afe1a688SKonstantin Belousov .sv_set_syscall_retval = cpu_set_syscall_retval, 88afe1a688SKonstantin Belousov .sv_fetch_syscall_args = cpu_fetch_syscall_args, 89afe1a688SKonstantin Belousov .sv_syscallnames = syscallnames, 909ce875d9SKonstantin Belousov .sv_shared_page_base = SHAREDPAGE_LA48, 916297a3d8SKonstantin Belousov .sv_shared_page_len = PAGE_SIZE, 92e5d81ef1SDmitry Chagin .sv_schedtail = NULL, 9391d1786fSDmitry Chagin .sv_thread_detach = NULL, 94038c7205SDmitry Chagin .sv_trap = NULL, 9528a66fc3SKonstantin Belousov .sv_onexec_old = exec_onexec_old, 9628a66fc3SKonstantin Belousov .sv_onexit = exit_onexit, 97de8374dfSDmitry Chagin .sv_set_fork_retval = x86_set_fork_retval, 98548a2ec4SAndrew Turner .sv_regset_begin = SET_BEGIN(__elfN(regset)), 99548a2ec4SAndrew Turner .sv_regset_end = SET_LIMIT(__elfN(regset)), 1003ebc1248SPeter Wemm }; 1019ce875d9SKonstantin Belousov 1029ce875d9SKonstantin Belousov struct sysentvec elf64_freebsd_sysvec_la57 = { 1039ce875d9SKonstantin Belousov .sv_size = SYS_MAXSYSCALL, 1049ce875d9SKonstantin Belousov .sv_table = sysent, 1059ce875d9SKonstantin Belousov .sv_fixup = __elfN(freebsd_fixup), 1069ce875d9SKonstantin Belousov .sv_sendsig = sendsig, 107ab4524b3SKonstantin Belousov .sv_sigcode = _binary_elf_vdso_so_1_start, 108ab4524b3SKonstantin Belousov .sv_szsigcode = (int *)&_binary_elf_vdso_so_1_size, 109ab4524b3SKonstantin Belousov .sv_sigcodeoff = VDSO_SIGCODE_OFFSET, 1109ce875d9SKonstantin Belousov .sv_name = "FreeBSD ELF64", 1119ce875d9SKonstantin Belousov .sv_coredump = __elfN(coredump), 112435754a5SEdward Tomasz Napierala .sv_elf_core_osabi = ELFOSABI_FREEBSD, 113435754a5SEdward Tomasz Napierala .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR, 114435754a5SEdward Tomasz Napierala .sv_elf_core_prepare_notes = __elfN(prepare_notes), 1159ce875d9SKonstantin Belousov .sv_imgact_try = NULL, 1169ce875d9SKonstantin Belousov .sv_minsigstksz = MINSIGSTKSZ, 1179ce875d9SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 1189ce875d9SKonstantin Belousov .sv_maxuser = VM_MAXUSER_ADDRESS_LA57, 1199ce875d9SKonstantin Belousov .sv_usrstack = USRSTACK_LA57, 1209ce875d9SKonstantin Belousov .sv_psstrings = PS_STRINGS_LA57, 1213fc21fddSMark Johnston .sv_psstringssz = sizeof(struct ps_strings), 1229ce875d9SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 1239ce875d9SKonstantin Belousov .sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs), 1249ce875d9SKonstantin Belousov .sv_copyout_strings = exec_copyout_strings, 1259ce875d9SKonstantin Belousov .sv_setregs = exec_setregs, 1269ce875d9SKonstantin Belousov .sv_fixlimit = NULL, 1279ce875d9SKonstantin Belousov .sv_maxssiz = NULL, 1289ce875d9SKonstantin Belousov .sv_flags = SV_ABI_FREEBSD | SV_ASLR | SV_LP64 | SV_SHP | 129ab4524b3SKonstantin Belousov SV_TIMEKEEP | SV_RNG_SEED_VER | SV_DSO_SIG, 1309ce875d9SKonstantin Belousov .sv_set_syscall_retval = cpu_set_syscall_retval, 1319ce875d9SKonstantin Belousov .sv_fetch_syscall_args = cpu_fetch_syscall_args, 1329ce875d9SKonstantin Belousov .sv_syscallnames = syscallnames, 1339ce875d9SKonstantin Belousov .sv_shared_page_base = SHAREDPAGE_LA57, 1349ce875d9SKonstantin Belousov .sv_shared_page_len = PAGE_SIZE, 1359ce875d9SKonstantin Belousov .sv_schedtail = NULL, 1369ce875d9SKonstantin Belousov .sv_thread_detach = NULL, 1379ce875d9SKonstantin Belousov .sv_trap = NULL, 13828a66fc3SKonstantin Belousov .sv_onexec_old = exec_onexec_old, 13928a66fc3SKonstantin Belousov .sv_onexit = exit_onexit, 140de8374dfSDmitry Chagin .sv_set_fork_retval= x86_set_fork_retval, 141548a2ec4SAndrew Turner .sv_regset_begin = SET_BEGIN(__elfN(regset)), 142548a2ec4SAndrew Turner .sv_regset_end = SET_LIMIT(__elfN(regset)), 1439ce875d9SKonstantin Belousov }; 1449ce875d9SKonstantin Belousov 1459ce875d9SKonstantin Belousov static void 1469ce875d9SKonstantin Belousov amd64_init_sysvecs(void *arg) 1479ce875d9SKonstantin Belousov { 1489ce875d9SKonstantin Belousov amd64_lower_shared_page(&elf64_freebsd_sysvec_la48); 1499ce875d9SKonstantin Belousov if (la57) { 1509ce875d9SKonstantin Belousov exec_sysvec_init(&elf64_freebsd_sysvec_la57); 1519ce875d9SKonstantin Belousov exec_sysvec_init_secondary(&elf64_freebsd_sysvec_la57, 1529ce875d9SKonstantin Belousov &elf64_freebsd_sysvec_la48); 1539ce875d9SKonstantin Belousov } else { 1549ce875d9SKonstantin Belousov exec_sysvec_init(&elf64_freebsd_sysvec_la48); 1559ce875d9SKonstantin Belousov } 1569ce875d9SKonstantin Belousov } 1579ce875d9SKonstantin Belousov SYSINIT(elf64_sysvec, SI_SUB_EXEC, SI_ORDER_ANY, amd64_init_sysvecs, NULL); 1583ebc1248SPeter Wemm 159cd155b56SDon Lewis void 160cd155b56SDon Lewis amd64_lower_shared_page(struct sysentvec *sv) 161cd155b56SDon Lewis { 162cd155b56SDon Lewis if (hw_lower_amd64_sharedpage != 0) { 163cd155b56SDon Lewis sv->sv_maxuser -= PAGE_SIZE; 164cd155b56SDon Lewis sv->sv_shared_page_base -= PAGE_SIZE; 165cd155b56SDon Lewis sv->sv_usrstack -= PAGE_SIZE; 166cd155b56SDon Lewis sv->sv_psstrings -= PAGE_SIZE; 167cd155b56SDon Lewis } 168cd155b56SDon Lewis } 169cd155b56SDon Lewis 170407f6757SJohn Baldwin static bool 1719ce875d9SKonstantin Belousov freebsd_brand_info_la57_img_compat(struct image_params *imgp, 1729ce875d9SKonstantin Belousov int32_t *osrel __unused, uint32_t *fctl0) 1739ce875d9SKonstantin Belousov { 1749ce875d9SKonstantin Belousov if ((imgp->proc->p_md.md_flags & P_MD_LA57) != 0) 175407f6757SJohn Baldwin return (true); 1769ce875d9SKonstantin Belousov if (fctl0 == NULL || (*fctl0 & NT_FREEBSD_FCTL_LA48) != 0) 177407f6757SJohn Baldwin return (false); 1789ce875d9SKonstantin Belousov if ((imgp->proc->p_md.md_flags & P_MD_LA48) != 0) 179407f6757SJohn Baldwin return (false); 180407f6757SJohn Baldwin return (true); 1819ce875d9SKonstantin Belousov } 182cd155b56SDon Lewis 1839ce875d9SKonstantin Belousov static Elf64_Brandinfo freebsd_brand_info_la48 = { 184a8d403e1SKonstantin Belousov .brand = ELFOSABI_FREEBSD, 185a8d403e1SKonstantin Belousov .machine = EM_X86_64, 186a8d403e1SKonstantin Belousov .compat_3_brand = "FreeBSD", 187a8d403e1SKonstantin Belousov .emul_path = NULL, 188a8d403e1SKonstantin Belousov .interp_path = "/libexec/ld-elf.so.1", 1899ce875d9SKonstantin Belousov .sysvec = &elf64_freebsd_sysvec_la48, 190a8d403e1SKonstantin Belousov .interp_newpath = NULL, 19132c01de2SDmitry Chagin .brand_note = &elf64_freebsd_brandnote, 1929ce875d9SKonstantin Belousov .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, 1933ebc1248SPeter Wemm }; 1943ebc1248SPeter Wemm 1959ce875d9SKonstantin Belousov static Elf64_Brandinfo freebsd_brand_info_la57 = { 1969ce875d9SKonstantin Belousov .brand = ELFOSABI_FREEBSD, 1979ce875d9SKonstantin Belousov .machine = EM_X86_64, 1989ce875d9SKonstantin Belousov .compat_3_brand = "FreeBSD", 1999ce875d9SKonstantin Belousov .emul_path = NULL, 2009ce875d9SKonstantin Belousov .interp_path = "/libexec/ld-elf.so.1", 2019ce875d9SKonstantin Belousov .sysvec = &elf64_freebsd_sysvec_la57, 2029ce875d9SKonstantin Belousov .interp_newpath = NULL, 2039ce875d9SKonstantin Belousov .brand_note = &elf64_freebsd_brandnote, 2049ce875d9SKonstantin Belousov .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, 2059ce875d9SKonstantin Belousov .header_supported = freebsd_brand_info_la57_img_compat, 2069ce875d9SKonstantin Belousov }; 2079ce875d9SKonstantin Belousov 2089ce875d9SKonstantin Belousov static void 2099ce875d9SKonstantin Belousov sysinit_register_elf64_brand_entries(void *arg __unused) 2109ce875d9SKonstantin Belousov { 2119ce875d9SKonstantin Belousov /* 2129ce875d9SKonstantin Belousov * _57 must go first so it can either claim the image or hand 2139ce875d9SKonstantin Belousov * it to _48. 2149ce875d9SKonstantin Belousov */ 2159ce875d9SKonstantin Belousov if (la57) 2169ce875d9SKonstantin Belousov elf64_insert_brand_entry(&freebsd_brand_info_la57); 2179ce875d9SKonstantin Belousov elf64_insert_brand_entry(&freebsd_brand_info_la48); 2189ce875d9SKonstantin Belousov } 21952bf2041SBjoern A. Zeeb SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_FIRST, 2209ce875d9SKonstantin Belousov sysinit_register_elf64_brand_entries, NULL); 221033f58dfSPeter Wemm 2229b68618dSPeter Wemm static Elf64_Brandinfo freebsd_brand_oinfo = { 223a8d403e1SKonstantin Belousov .brand = ELFOSABI_FREEBSD, 224a8d403e1SKonstantin Belousov .machine = EM_X86_64, 225a8d403e1SKonstantin Belousov .compat_3_brand = "FreeBSD", 226a8d403e1SKonstantin Belousov .emul_path = NULL, 227a8d403e1SKonstantin Belousov .interp_path = "/usr/libexec/ld-elf.so.1", 2289ce875d9SKonstantin Belousov .sysvec = &elf64_freebsd_sysvec_la48, 229a8d403e1SKonstantin Belousov .interp_newpath = NULL, 23032c01de2SDmitry Chagin .brand_note = &elf64_freebsd_brandnote, 231cd899aadSDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 2329b68618dSPeter Wemm }; 2339b68618dSPeter Wemm 2349b68618dSPeter Wemm SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY, 2359ce875d9SKonstantin Belousov (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_oinfo); 2369b68618dSPeter Wemm 23789ffc202SBjoern A. Zeeb static Elf64_Brandinfo kfreebsd_brand_info = { 23889ffc202SBjoern A. Zeeb .brand = ELFOSABI_FREEBSD, 23989ffc202SBjoern A. Zeeb .machine = EM_X86_64, 24089ffc202SBjoern A. Zeeb .compat_3_brand = "FreeBSD", 24189ffc202SBjoern A. Zeeb .emul_path = NULL, 24289ffc202SBjoern A. Zeeb .interp_path = "/lib/ld-kfreebsd-x86-64.so.1", 2439ce875d9SKonstantin Belousov .sysvec = &elf64_freebsd_sysvec_la48, 24489ffc202SBjoern A. Zeeb .interp_newpath = NULL, 24589ffc202SBjoern A. Zeeb .brand_note = &elf64_kfreebsd_brandnote, 246ecc2fda8SBjoern A. Zeeb .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE_MANDATORY 24789ffc202SBjoern A. Zeeb }; 24889ffc202SBjoern A. Zeeb 24989ffc202SBjoern A. Zeeb SYSINIT(kelf64, SI_SUB_EXEC, SI_ORDER_ANY, 2509ce875d9SKonstantin Belousov (sysinit_cfunc_t)elf64_insert_brand_entry, &kfreebsd_brand_info); 25189ffc202SBjoern A. Zeeb 2524da47b2fSMarcel Moolenaar void 253180e57e5SJohn Baldwin elf64_dump_thread(struct thread *td, void *dst, size_t *off) 2544da47b2fSMarcel Moolenaar { 255180e57e5SJohn Baldwin void *buf; 256180e57e5SJohn Baldwin size_t len; 2574da47b2fSMarcel Moolenaar 258180e57e5SJohn Baldwin len = 0; 259180e57e5SJohn Baldwin if (use_xsave) { 260180e57e5SJohn Baldwin if (dst != NULL) { 261180e57e5SJohn Baldwin fpugetregs(td); 262180e57e5SJohn Baldwin len += elf64_populate_note(NT_X86_XSTATE, 263180e57e5SJohn Baldwin get_pcb_user_save_td(td), dst, 264180e57e5SJohn Baldwin cpu_max_ext_state_size, &buf); 265180e57e5SJohn Baldwin *(uint64_t *)((char *)buf + X86_XSTATE_XCR0_OFFSET) = 266180e57e5SJohn Baldwin xsave_mask; 267180e57e5SJohn Baldwin } else 268180e57e5SJohn Baldwin len += elf64_populate_note(NT_X86_XSTATE, NULL, NULL, 269180e57e5SJohn Baldwin cpu_max_ext_state_size, NULL); 270180e57e5SJohn Baldwin } 271180e57e5SJohn Baldwin *off = len; 272180e57e5SJohn Baldwin } 2734da47b2fSMarcel Moolenaar 27436716fe2SMark Johnston bool 27536716fe2SMark Johnston elf_is_ifunc_reloc(Elf_Size r_info) 27636716fe2SMark Johnston { 27736716fe2SMark Johnston 27836716fe2SMark Johnston return (ELF_R_TYPE(r_info) == R_X86_64_IRELATIVE); 27936716fe2SMark Johnston } 2807035cf14SKonstantin Belousov 281bde362f5SPeter Wemm /* Process one elf relocation with addend. */ 2827251b4bfSJake Burkholder static int 283e8855d4fSPeter Wemm elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, 284fcf7a481SAndrew Turner int type, bool late_ifunc, elf_lookup_fn lookup) 285033f58dfSPeter Wemm { 286e8855d4fSPeter Wemm Elf64_Addr *where, val; 287e8855d4fSPeter Wemm Elf32_Addr *where32, val32; 288f1d19042SArchie Cobbs Elf_Addr addr; 289aa855a59SPeter Wemm Elf_Addr addend; 290757686b1SMarcel Moolenaar Elf_Size rtype, symidx; 291aa855a59SPeter Wemm const Elf_Rel *rel; 292aa855a59SPeter Wemm const Elf_Rela *rela; 293cff8c6f2SKonstantin Belousov int error; 294033f58dfSPeter Wemm 295aa855a59SPeter Wemm switch (type) { 296aa855a59SPeter Wemm case ELF_RELOC_REL: 2970a5e03ddSMatthew Dillon rel = (const Elf_Rel *)data; 298aa855a59SPeter Wemm where = (Elf_Addr *) (relocbase + rel->r_offset); 299aa855a59SPeter Wemm rtype = ELF_R_TYPE(rel->r_info); 300d297ad16SMarcel Moolenaar symidx = ELF_R_SYM(rel->r_info); 301910bb7dbSPeter Wemm /* Addend is 32 bit on 32 bit relocs */ 302910bb7dbSPeter Wemm switch (rtype) { 303910bb7dbSPeter Wemm case R_X86_64_PC32: 304910bb7dbSPeter Wemm case R_X86_64_32S: 305f9875149SGleb Smirnoff case R_X86_64_PLT32: 306910bb7dbSPeter Wemm addend = *(Elf32_Addr *)where; 307910bb7dbSPeter Wemm break; 308910bb7dbSPeter Wemm default: 309910bb7dbSPeter Wemm addend = *where; 310910bb7dbSPeter Wemm break; 311910bb7dbSPeter Wemm } 312aa855a59SPeter Wemm break; 313aa855a59SPeter Wemm case ELF_RELOC_RELA: 3140a5e03ddSMatthew Dillon rela = (const Elf_Rela *)data; 315aa855a59SPeter Wemm where = (Elf_Addr *) (relocbase + rela->r_offset); 316aa855a59SPeter Wemm addend = rela->r_addend; 317aa855a59SPeter Wemm rtype = ELF_R_TYPE(rela->r_info); 318d297ad16SMarcel Moolenaar symidx = ELF_R_SYM(rela->r_info); 319aa855a59SPeter Wemm break; 320aa855a59SPeter Wemm default: 321aa855a59SPeter Wemm panic("unknown reloc type %d\n", type); 322aa855a59SPeter Wemm } 323033f58dfSPeter Wemm 324fcf7a481SAndrew Turner if (late_ifunc) { 325fcf7a481SAndrew Turner KASSERT(type == ELF_RELOC_RELA, 326fcf7a481SAndrew Turner ("Only RELA ifunc relocations are supported")); 327fcf7a481SAndrew Turner if (rtype != R_X86_64_IRELATIVE) 328fcf7a481SAndrew Turner return (0); 329fcf7a481SAndrew Turner } 330fcf7a481SAndrew Turner 331aa855a59SPeter Wemm switch (rtype) { 332afa88623SPeter Wemm case R_X86_64_NONE: /* none */ 333033f58dfSPeter Wemm break; 334033f58dfSPeter Wemm 335afa88623SPeter Wemm case R_X86_64_64: /* S + A */ 336cff8c6f2SKonstantin Belousov error = lookup(lf, symidx, 1, &addr); 337e8855d4fSPeter Wemm val = addr + addend; 338cff8c6f2SKonstantin Belousov if (error != 0) 3398481aab1SMitchell Horne return (-1); 340e8855d4fSPeter Wemm if (*where != val) 341e8855d4fSPeter Wemm *where = val; 342033f58dfSPeter Wemm break; 343033f58dfSPeter Wemm 344afa88623SPeter Wemm case R_X86_64_PC32: /* S + A - P */ 345f9875149SGleb Smirnoff case R_X86_64_PLT32: /* L + A - P, L is PLT location for 346f9875149SGleb Smirnoff the symbol, which we treat as S */ 347cff8c6f2SKonstantin Belousov error = lookup(lf, symidx, 1, &addr); 348e8855d4fSPeter Wemm where32 = (Elf32_Addr *)where; 349e8855d4fSPeter Wemm val32 = (Elf32_Addr)(addr + addend - (Elf_Addr)where); 350cff8c6f2SKonstantin Belousov if (error != 0) 3518481aab1SMitchell Horne return (-1); 352e8855d4fSPeter Wemm if (*where32 != val32) 353e8855d4fSPeter Wemm *where32 = val32; 354e8855d4fSPeter Wemm break; 355e8855d4fSPeter Wemm 356e8855d4fSPeter Wemm case R_X86_64_32S: /* S + A sign extend */ 357cff8c6f2SKonstantin Belousov error = lookup(lf, symidx, 1, &addr); 358e8855d4fSPeter Wemm val32 = (Elf32_Addr)(addr + addend); 359e8855d4fSPeter Wemm where32 = (Elf32_Addr *)where; 360cff8c6f2SKonstantin Belousov if (error != 0) 3618481aab1SMitchell Horne return (-1); 362e8855d4fSPeter Wemm if (*where32 != val32) 363e8855d4fSPeter Wemm *where32 = val32; 364033f58dfSPeter Wemm break; 365033f58dfSPeter Wemm 366afa88623SPeter Wemm case R_X86_64_COPY: /* none */ 367033f58dfSPeter Wemm /* 368033f58dfSPeter Wemm * There shouldn't be copy relocations in kernel 369033f58dfSPeter Wemm * objects. 370033f58dfSPeter Wemm */ 3718481aab1SMitchell Horne printf("kldload: unexpected R_COPY relocation, " 3728481aab1SMitchell Horne "symbol index %ld\n", symidx); 3739ea63320SKonstantin Belousov return (-1); 374033f58dfSPeter Wemm 375afa88623SPeter Wemm case R_X86_64_GLOB_DAT: /* S */ 376901b68c1SPeter Wemm case R_X86_64_JMP_SLOT: /* XXX need addend + offset */ 377cff8c6f2SKonstantin Belousov error = lookup(lf, symidx, 1, &addr); 378cff8c6f2SKonstantin Belousov if (error != 0) 3798481aab1SMitchell Horne return (-1); 380033f58dfSPeter Wemm if (*where != addr) 381033f58dfSPeter Wemm *where = addr; 382033f58dfSPeter Wemm break; 383033f58dfSPeter Wemm 384afa88623SPeter Wemm case R_X86_64_RELATIVE: /* B + A */ 38538dae42cSMark Johnston addr = elf_relocaddr(lf, relocbase + addend); 386e8855d4fSPeter Wemm val = addr; 387e8855d4fSPeter Wemm if (*where != val) 388e8855d4fSPeter Wemm *where = val; 389033f58dfSPeter Wemm break; 390033f58dfSPeter Wemm 3917035cf14SKonstantin Belousov case R_X86_64_IRELATIVE: 3927035cf14SKonstantin Belousov addr = relocbase + addend; 3937035cf14SKonstantin Belousov val = ((Elf64_Addr (*)(void))addr)(); 3947035cf14SKonstantin Belousov if (*where != val) 3957035cf14SKonstantin Belousov *where = val; 3967035cf14SKonstantin Belousov break; 3977035cf14SKonstantin Belousov 398033f58dfSPeter Wemm default: 3998481aab1SMitchell Horne printf("kldload: unexpected relocation type %ld, " 4008481aab1SMitchell Horne "symbol index %ld\n", rtype, symidx); 4019ea63320SKonstantin Belousov return (-1); 402033f58dfSPeter Wemm } 403033f58dfSPeter Wemm return (0); 404033f58dfSPeter Wemm } 4051aeb23cdSMarcel Moolenaar 4061aeb23cdSMarcel Moolenaar int 407e8855d4fSPeter Wemm elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, 408e8855d4fSPeter Wemm elf_lookup_fn lookup) 4097251b4bfSJake Burkholder { 4107251b4bfSJake Burkholder 411fcf7a481SAndrew Turner return (elf_reloc_internal(lf, relocbase, data, type, false, lookup)); 4127251b4bfSJake Burkholder } 4137251b4bfSJake Burkholder 4147251b4bfSJake Burkholder int 415e8855d4fSPeter Wemm elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, 416e8855d4fSPeter Wemm int type, elf_lookup_fn lookup) 4177251b4bfSJake Burkholder { 4187251b4bfSJake Burkholder 419fcf7a481SAndrew Turner return (elf_reloc_internal(lf, relocbase, data, type, false, lookup)); 420fcf7a481SAndrew Turner } 421fcf7a481SAndrew Turner 422fcf7a481SAndrew Turner int 423fcf7a481SAndrew Turner elf_reloc_late(linker_file_t lf, Elf_Addr relocbase, const void *data, 424fcf7a481SAndrew Turner int type, elf_lookup_fn lookup) 425fcf7a481SAndrew Turner { 426fcf7a481SAndrew Turner 427fcf7a481SAndrew Turner return (elf_reloc_internal(lf, relocbase, data, type, true, lookup)); 4287251b4bfSJake Burkholder } 4297251b4bfSJake Burkholder 4307251b4bfSJake Burkholder int 4311aeb23cdSMarcel Moolenaar elf_cpu_load_file(linker_file_t lf __unused) 4321aeb23cdSMarcel Moolenaar { 4331aeb23cdSMarcel Moolenaar 4341aeb23cdSMarcel Moolenaar return (0); 4351aeb23cdSMarcel Moolenaar } 4361aeb23cdSMarcel Moolenaar 4371aeb23cdSMarcel Moolenaar int 4381aeb23cdSMarcel Moolenaar elf_cpu_unload_file(linker_file_t lf __unused) 4391aeb23cdSMarcel Moolenaar { 4401aeb23cdSMarcel Moolenaar 4411aeb23cdSMarcel Moolenaar return (0); 4421aeb23cdSMarcel Moolenaar } 44338f69a61SBrandon Bergren 44438f69a61SBrandon Bergren int 44530693808SBrandon Bergren elf_cpu_parse_dynamic(caddr_t loadbase __unused, Elf_Dyn *dynamic __unused) 44638f69a61SBrandon Bergren { 44738f69a61SBrandon Bergren 44838f69a61SBrandon Bergren return (0); 44938f69a61SBrandon Bergren } 450