1 /*- 2 * Copyright (c) 2003 Jake Burkholder. 3 * Copyright 1996-1998 John D. Polstra. 4 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 5 * Copyright (c) 1998 Peter Wemm <peter@freebsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/types.h> 31 #include <machine/elf.h> 32 33 #include <stand.h> 34 35 #define FREEBSD_ELF 36 #include <sys/link_elf.h> 37 38 #include "bootstrap.h" 39 40 #define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) 41 42 /* 43 * Apply a single intra-module relocation to the data. `relbase' is the 44 * target relocation base for the section (i.e. it corresponds to where 45 * r_offset == 0). `dataaddr' is the relocated address corresponding to 46 * the start of the data, and `len' is the number of bytes. 47 */ 48 int 49 __elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata, 50 int reltype, Elf_Addr relbase, Elf_Addr dataaddr, void *data, size_t len) 51 { 52 #if (defined(__aarch64__) || defined(__amd64__) || defined(__i386__)) && \ 53 __ELF_WORD_SIZE == 64 54 Elf64_Addr *where, val; 55 Elf_Addr addend, addr; 56 Elf_Size rtype; 57 #if defined(__amd64__) || defined(__i386__) 58 Elf_Size symidx; 59 #endif 60 const Elf_Rel *rel; 61 const Elf_Rela *rela; 62 63 switch (reltype) { 64 case ELF_RELOC_REL: 65 rel = (const Elf_Rel *)reldata; 66 where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - 67 dataaddr); 68 addend = 0; 69 rtype = ELF_R_TYPE(rel->r_info); 70 #if defined(__amd64__) || defined(__i386__) 71 symidx = ELF_R_SYM(rel->r_info); 72 #endif 73 addend = 0; 74 break; 75 case ELF_RELOC_RELA: 76 rela = (const Elf_Rela *)reldata; 77 where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - 78 dataaddr); 79 addend = rela->r_addend; 80 rtype = ELF_R_TYPE(rela->r_info); 81 #if defined(__amd64__) || defined(__i386__) 82 symidx = ELF_R_SYM(rela->r_info); 83 #endif 84 break; 85 default: 86 return (EINVAL); 87 } 88 89 if ((char *)where < (char *)data || (char *)where >= (char *)data + len) 90 return (0); 91 92 if (reltype == ELF_RELOC_REL) 93 addend = *where; 94 95 #if defined(__aarch64__) 96 #define RELOC_RELATIVE R_AARCH64_RELATIVE 97 #define RELOC_IRELATIVE R_AARCH64_IRELATIVE 98 #elif defined(__amd64__) || defined(__i386__) 99 /* XXX, definitions not available on i386. */ 100 #define R_X86_64_64 1 101 #define R_X86_64_RELATIVE 8 102 #define R_X86_64_IRELATIVE 37 103 104 #define RELOC_RELATIVE R_X86_64_RELATIVE 105 #define RELOC_IRELATIVE R_X86_64_IRELATIVE 106 #endif 107 108 switch (rtype) { 109 case RELOC_RELATIVE: 110 addr = (Elf_Addr)addend + relbase; 111 val = addr; 112 memcpy(where, &val, sizeof(val)); 113 break; 114 case RELOC_IRELATIVE: 115 /* leave it to kernel */ 116 break; 117 #if defined(__amd64__) || defined(__i386__) 118 case R_X86_64_64: /* S + A */ 119 addr = symaddr(ef, symidx); 120 if (addr == 0) 121 return (ESRCH); 122 val = addr + addend; 123 *where = val; 124 break; 125 #endif 126 default: 127 printf("\nunhandled relocation type %u\n", (u_int)rtype); 128 return (EFTYPE); 129 } 130 131 return (0); 132 #elif defined(__i386__) && __ELF_WORD_SIZE == 32 133 Elf_Addr addend, addr, *where, val; 134 Elf_Size rtype, symidx; 135 const Elf_Rel *rel; 136 const Elf_Rela *rela; 137 138 switch (reltype) { 139 case ELF_RELOC_REL: 140 rel = (const Elf_Rel *)reldata; 141 where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - 142 dataaddr); 143 addend = 0; 144 rtype = ELF_R_TYPE(rel->r_info); 145 symidx = ELF_R_SYM(rel->r_info); 146 addend = 0; 147 break; 148 case ELF_RELOC_RELA: 149 rela = (const Elf_Rela *)reldata; 150 where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - 151 dataaddr); 152 addend = rela->r_addend; 153 rtype = ELF_R_TYPE(rela->r_info); 154 symidx = ELF_R_SYM(rela->r_info); 155 break; 156 default: 157 return (EINVAL); 158 } 159 160 if ((char *)where < (char *)data || (char *)where >= (char *)data + len) 161 return (0); 162 163 if (reltype == ELF_RELOC_REL) 164 addend = *where; 165 166 /* XXX, definitions not available on amd64. */ 167 #define R_386_32 1 /* Add symbol value. */ 168 #define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ 169 #define R_386_RELATIVE 8 /* Add load address of shared object. */ 170 #define R_386_IRELATIVE 42 171 172 switch (rtype) { 173 case R_386_RELATIVE: 174 addr = addend + relbase; 175 *where = addr; 176 break; 177 case R_386_32: /* S + A */ 178 addr = symaddr(ef, symidx); 179 if (addr == 0) 180 return (ESRCH); 181 val = addr + addend; 182 *where = val; 183 break; 184 case R_386_IRELATIVE: 185 /* leave it to kernel */ 186 break; 187 default: 188 printf("\nunhandled relocation type %u\n", (u_int)rtype); 189 return (EFTYPE); 190 } 191 192 return (0); 193 #elif defined(__powerpc__) || defined(__riscv) 194 Elf_Size w; 195 const Elf_Rela *rela; 196 197 switch (reltype) { 198 case ELF_RELOC_RELA: 199 rela = reldata; 200 if (relbase + rela->r_offset >= dataaddr && 201 relbase + rela->r_offset < dataaddr + len) { 202 switch (ELF_R_TYPE(rela->r_info)) { 203 #if defined(__powerpc__) 204 case R_PPC_RELATIVE: 205 #elif defined(__riscv) 206 case R_RISCV_RELATIVE: 207 #endif 208 w = relbase + rela->r_addend; 209 bcopy(&w, (u_char *)data + (relbase + 210 rela->r_offset - dataaddr), sizeof(w)); 211 break; 212 default: 213 printf("\nunhandled relocation type %u\n", 214 (u_int)ELF_R_TYPE(rela->r_info)); 215 return (EFTYPE); 216 } 217 } 218 break; 219 } 220 221 return (0); 222 #else 223 return (EOPNOTSUPP); 224 #endif 225 } 226