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 29static bool 30is_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 45static 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 62status_t 63boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, Elf32_Rel *rel, 64 int relLength) 65#else 66int 67arch_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 181status_t 182boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image, 183 Elf32_Rela *rel, int relLength) 184#else 185int 186arch_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 204status_t 205boot_arch_elf_relocate_rel(preloaded_elf64_image* image, Elf64_Rel* rel, 206 int relLength) 207#else 208int 209arch_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 219status_t 220boot_arch_elf_relocate_rela(preloaded_elf64_image* image, Elf64_Rela* rel, 221 int relLength) 222#else 223int 224arch_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