1 /* 2 * Copyright 2004-2018, Haiku Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Copyright 2002, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 10 #ifdef _BOOT_MODE 11 # include <boot/arch.h> 12 #endif 13 14 #include <KernelExport.h> 15 16 #include <elf_priv.h> 17 #include <arch/elf.h> 18 19 20 //#define TRACE_ARCH_ELF 21 #ifdef TRACE_ARCH_ELF 22 # define TRACE(x) dprintf x 23 #else 24 # define TRACE(x) ; 25 #endif 26 27 28 #ifndef _BOOT_MODE 29 static bool 30 is_in_image(struct elf_image_info *image, addr_t address) 31 { 32 return (address >= image->text_region.start 33 && address < image->text_region.start + image->text_region.size) 34 || (address >= image->data_region.start 35 && address < image->data_region.start + image->data_region.size); 36 } 37 #endif // !_BOOT_MODE 38 39 40 #if !defined(__x86_64__) || defined(ELF32_COMPAT) \ 41 || (defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF32)) 42 43 44 #ifdef TRACE_ARCH_ELF 45 static const char *kRelocations[] = { 46 "R_386_NONE", 47 "R_386_32", /* add symbol value */ 48 "R_386_PC32", /* add PC relative symbol value */ 49 "R_386_GOT32", /* add PC relative GOT offset */ 50 "R_386_PLT32", /* add PC relative PLT offset */ 51 "R_386_COPY", /* copy data from shared object */ 52 "R_386_GLOB_DAT", /* set GOT entry to data address */ 53 "R_386_JMP_SLOT", /* set GOT entry to code address */ 54 "R_386_RELATIVE", /* add load address of shared object */ 55 "R_386_GOTOFF", /* add GOT relative symbol address */ 56 "R_386_GOTPC", /* add PC relative GOT table address */ 57 }; 58 #endif 59 60 61 #ifdef _BOOT_MODE 62 status_t 63 boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, Elf32_Rel *rel, 64 int relLength) 65 #else 66 int 67 arch_elf_relocate_rel(struct elf_image_info *image, 68 struct elf_image_info *resolveImage, Elf32_Rel *rel, int relLength) 69 #endif 70 { 71 Elf32_Addr S; 72 uint32 A; 73 uint32 P; 74 uint32 finalAddress; 75 uint32 *resolveAddress; 76 int i; 77 78 S = A = P = 0; 79 80 for (i = 0; i * (int)sizeof(Elf32_Rel) < relLength; i++) { 81 TRACE(("looking at rel type %s, offset 0x%" B_PRIx32 "\n", 82 kRelocations[ELF32_R_TYPE(rel[i].r_info)], rel[i].r_offset)); 83 84 // calc S 85 switch (ELF32_R_TYPE(rel[i].r_info)) { 86 case R_386_32: 87 case R_386_PC32: 88 case R_386_GLOB_DAT: 89 case R_386_JMP_SLOT: 90 case R_386_GOTOFF: 91 { 92 Elf32_Sym *symbol; 93 status_t status; 94 95 symbol = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); 96 97 #ifdef _BOOT_MODE 98 status = boot_elf_resolve_symbol(image, symbol, &S); 99 #else 100 status = elf_resolve_symbol(image, symbol, resolveImage, &S); 101 #endif 102 if (status < B_OK) 103 return status; 104 #ifndef _BOOT_MODE 105 TRACE(("S 0x%08" B_PRIx32 " (%s)\n", S, SYMNAME(image, symbol))); 106 #endif 107 } 108 } 109 // calc A 110 switch (ELF32_R_TYPE(rel[i].r_info)) { 111 case R_386_32: 112 case R_386_PC32: 113 case R_386_GOT32: 114 case R_386_PLT32: 115 case R_386_RELATIVE: 116 case R_386_GOTOFF: 117 case R_386_GOTPC: 118 #ifndef _BOOT_MODE 119 A = *(uint32 *)(image->text_region.delta + rel[i].r_offset); 120 #else 121 A = boot_elf32_get_relocation(image->text_region.delta + rel[i].r_offset); 122 #endif 123 TRACE(("A 0x%08" B_PRIx32 "\n", A)); 124 break; 125 } 126 // calc P 127 switch (ELF32_R_TYPE(rel[i].r_info)) { 128 case R_386_PC32: 129 case R_386_GOT32: 130 case R_386_PLT32: 131 case R_386_GOTPC: 132 P = image->text_region.delta + rel[i].r_offset; 133 TRACE(("P 0x%08" B_PRIx32 "\n", P)); 134 break; 135 } 136 137 switch (ELF32_R_TYPE(rel[i].r_info)) { 138 case R_386_NONE: 139 continue; 140 case R_386_32: 141 finalAddress = S + A; 142 break; 143 case R_386_PC32: 144 finalAddress = S + A - P; 145 break; 146 case R_386_RELATIVE: 147 // B + A; 148 finalAddress = image->text_region.delta + A; 149 break; 150 case R_386_JMP_SLOT: 151 case R_386_GLOB_DAT: 152 finalAddress = S; 153 break; 154 155 default: 156 dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n", 157 ELF32_R_TYPE(rel[i].r_info)); 158 return B_BAD_DATA; 159 } 160 161 resolveAddress = (uint32 *)(addr_t)(image->text_region.delta + rel[i].r_offset); 162 #ifndef _BOOT_MODE 163 if (!is_in_image(image, (addr_t)resolveAddress)) { 164 dprintf("arch_elf_relocate_rel: invalid offset 0x%" B_PRIx32 "\n", 165 rel[i].r_offset); 166 return B_BAD_ADDRESS; 167 } 168 *resolveAddress = finalAddress; 169 #else 170 boot_elf32_set_relocation((Elf32_Addr)(addr_t)resolveAddress, finalAddress); 171 #endif 172 TRACE(("-> offset 0x%08" B_PRIx32 "x (0x%08" B_PRIx32 ") = 0x%08" B_PRIx32 "\n", 173 image->text_region.delta + rel[i].r_offset, rel[i].r_offset, finalAddress)); 174 } 175 176 return B_NO_ERROR; 177 } 178 179 180 #ifdef _BOOT_MODE 181 status_t 182 boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image, 183 Elf32_Rela *rel, int relLength) 184 #else 185 int 186 arch_elf_relocate_rela(struct elf_image_info *image, 187 struct elf_image_info *resolveImage, Elf32_Rela *rel, int relLength) 188 #endif 189 { 190 dprintf("arch_elf_relocate_rela: not supported on x86\n"); 191 return B_ERROR; 192 } 193 194 195 #endif // !defined(__x86_64__) || defined(ELF32_COMPAT) || 196 // (defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF32)) 197 198 199 #if (defined(__x86_64__) && !defined(ELF32_COMPAT)) || \ 200 (defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF64)) 201 202 203 #ifdef _BOOT_MODE 204 status_t 205 boot_arch_elf_relocate_rel(preloaded_elf64_image* image, Elf64_Rel* rel, 206 int relLength) 207 #else 208 int 209 arch_elf_relocate_rel(struct elf_image_info *image, 210 struct elf_image_info *resolveImage, Elf64_Rel *rel, int relLength) 211 #endif 212 { 213 dprintf("arch_elf_relocate_rel: not supported on x86_64\n"); 214 return B_ERROR; 215 } 216 217 218 #ifdef _BOOT_MODE 219 status_t 220 boot_arch_elf_relocate_rela(preloaded_elf64_image* image, Elf64_Rela* rel, 221 int relLength) 222 #else 223 int 224 arch_elf_relocate_rela(struct elf_image_info *image, 225 struct elf_image_info *resolveImage, Elf64_Rela *rel, int relLength) 226 #endif 227 { 228 for (int i = 0; i < relLength / (int)sizeof(Elf64_Rela); i++) { 229 int type = ELF64_R_TYPE(rel[i].r_info); 230 int symIndex = ELF64_R_SYM(rel[i].r_info); 231 Elf64_Addr symAddr = 0; 232 233 // Resolve the symbol, if any. 234 if (symIndex != 0) { 235 Elf64_Sym* symbol = SYMBOL(image, symIndex); 236 237 status_t status; 238 #ifdef _BOOT_MODE 239 status = boot_elf_resolve_symbol(image, symbol, &symAddr); 240 #else 241 status = elf_resolve_symbol(image, symbol, resolveImage, &symAddr); 242 #endif 243 if (status < B_OK) 244 return status; 245 } 246 247 // Address of the relocation. 248 Elf64_Addr relocAddr = image->text_region.delta + rel[i].r_offset; 249 250 // Calculate the relocation value. 251 Elf64_Addr relocValue; 252 switch (type) { 253 case R_X86_64_NONE: 254 continue; 255 case R_X86_64_64: 256 relocValue = symAddr + rel[i].r_addend; 257 break; 258 case R_X86_64_PC32: 259 relocValue = symAddr + rel[i].r_addend - rel[i].r_offset; 260 break; 261 case R_X86_64_GLOB_DAT: 262 case R_X86_64_JUMP_SLOT: 263 relocValue = symAddr + rel[i].r_addend; 264 break; 265 case R_X86_64_RELATIVE: 266 relocValue = image->text_region.delta + rel[i].r_addend; 267 break; 268 default: 269 dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", 270 type); 271 return B_BAD_DATA; 272 } 273 #ifdef _BOOT_MODE 274 boot_elf64_set_relocation(relocAddr, relocValue); 275 #else 276 if (!is_in_image(image, relocAddr)) { 277 dprintf("arch_elf_relocate_rela: invalid offset %#lx\n", 278 rel[i].r_offset); 279 return B_BAD_ADDRESS; 280 } 281 282 if (type == R_X86_64_PC32) 283 *(Elf32_Addr *)relocAddr = relocValue; 284 else 285 *(Elf64_Addr *)relocAddr = relocValue; 286 #endif 287 } 288 289 return B_OK; 290 } 291 292 293 #endif // (defined(__x86_64__) && !defined(ELF32_COMPAT)) || 294 // (defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF64)) 295