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) && _BOOT_PLATFORM != efi) 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 elf_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%lx\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 TRACE(("S %p (%s)\n", (void *)S, SYMNAME(image, symbol))); 105 } 106 } 107 // calc A 108 switch (ELF32_R_TYPE(rel[i].r_info)) { 109 case R_386_32: 110 case R_386_PC32: 111 case R_386_GOT32: 112 case R_386_PLT32: 113 case R_386_RELATIVE: 114 case R_386_GOTOFF: 115 case R_386_GOTPC: 116 #ifndef _BOOT_MODE 117 A = *(uint32 *)(image->text_region.delta + rel[i].r_offset); 118 #else 119 A = boot_elf32_get_relocation(image->text_region.delta + rel[i].r_offset); 120 #endif 121 TRACE(("A %p\n", (void *)A)); 122 break; 123 } 124 // calc P 125 switch (ELF32_R_TYPE(rel[i].r_info)) { 126 case R_386_PC32: 127 case R_386_GOT32: 128 case R_386_PLT32: 129 case R_386_GOTPC: 130 P = image->text_region.delta + rel[i].r_offset; 131 TRACE(("P %p\n", (void *)P)); 132 break; 133 } 134 135 switch (ELF32_R_TYPE(rel[i].r_info)) { 136 case R_386_NONE: 137 continue; 138 case R_386_32: 139 finalAddress = S + A; 140 break; 141 case R_386_PC32: 142 finalAddress = S + A - P; 143 break; 144 case R_386_RELATIVE: 145 // B + A; 146 finalAddress = image->text_region.delta + A; 147 break; 148 case R_386_JMP_SLOT: 149 case R_386_GLOB_DAT: 150 finalAddress = S; 151 break; 152 153 default: 154 dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n", 155 ELF32_R_TYPE(rel[i].r_info)); 156 return B_BAD_DATA; 157 } 158 159 resolveAddress = (uint32 *)(image->text_region.delta + rel[i].r_offset); 160 #ifndef _BOOT_MODE 161 if (!is_in_image(image, (addr_t)resolveAddress)) { 162 dprintf("arch_elf_relocate_rel: invalid offset %#lx\n", 163 rel[i].r_offset); 164 return B_BAD_ADDRESS; 165 } 166 *resolveAddress = finalAddress; 167 #else 168 boot_elf32_set_relocation((Elf32_Addr)resolveAddress, finalAddress); 169 #endif 170 TRACE(("-> offset %#lx (%#lx) = %#lx\n", 171 (image->text_region.delta + rel[i].r_offset), rel[i].r_offset, finalAddress)); 172 } 173 174 return B_NO_ERROR; 175 } 176 177 178 #ifdef _BOOT_MODE 179 status_t 180 boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image, 181 Elf32_Rela *rel, int relLength) 182 #else 183 int 184 arch_elf_relocate_rela(struct elf_image_info *image, 185 struct elf_image_info *resolveImage, Elf32_Rela *rel, int relLength) 186 #endif 187 { 188 dprintf("arch_elf_relocate_rela: not supported on x86\n"); 189 return B_ERROR; 190 } 191 192 193 #endif // !defined(__x86_64__) || defined(ELF32_COMPAT) || 194 // (defined(_BOOT_MODE) && _BOOT_PLATFORM != efi) 195 196 197 #if (defined(__x86_64__) && !defined(ELF32_COMPAT)) || \ 198 (defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF64)) 199 200 201 #ifdef _BOOT_MODE 202 status_t 203 boot_arch_elf_relocate_rel(preloaded_elf64_image* image, Elf64_Rel* rel, 204 int relLength) 205 #else 206 int 207 arch_elf_relocate_rel(struct elf_image_info *image, 208 struct elf_image_info *resolveImage, Elf64_Rel *rel, int relLength) 209 #endif 210 { 211 dprintf("arch_elf_relocate_rel: not supported on x86_64\n"); 212 return B_ERROR; 213 } 214 215 216 #ifdef _BOOT_MODE 217 status_t 218 boot_arch_elf_relocate_rela(preloaded_elf64_image* image, Elf64_Rela* rel, 219 int relLength) 220 #else 221 int 222 arch_elf_relocate_rela(struct elf_image_info *image, 223 struct elf_image_info *resolveImage, Elf64_Rela *rel, int relLength) 224 #endif 225 { 226 for (int i = 0; i < relLength / (int)sizeof(Elf64_Rela); i++) { 227 int type = ELF64_R_TYPE(rel[i].r_info); 228 int symIndex = ELF64_R_SYM(rel[i].r_info); 229 Elf64_Addr symAddr = 0; 230 231 // Resolve the symbol, if any. 232 if (symIndex != 0) { 233 Elf64_Sym* symbol = SYMBOL(image, symIndex); 234 235 status_t status; 236 #ifdef _BOOT_MODE 237 status = boot_elf_resolve_symbol(image, symbol, &symAddr); 238 #else 239 status = elf_resolve_symbol(image, symbol, resolveImage, &symAddr); 240 #endif 241 if (status < B_OK) 242 return status; 243 } 244 245 // Address of the relocation. 246 Elf64_Addr relocAddr = image->text_region.delta + rel[i].r_offset; 247 248 // Calculate the relocation value. 249 Elf64_Addr relocValue; 250 switch (type) { 251 case R_X86_64_NONE: 252 continue; 253 case R_X86_64_64: 254 relocValue = symAddr + rel[i].r_addend; 255 break; 256 case R_X86_64_PC32: 257 relocValue = symAddr + rel[i].r_addend - rel[i].r_offset; 258 break; 259 case R_X86_64_GLOB_DAT: 260 case R_X86_64_JUMP_SLOT: 261 relocValue = symAddr + rel[i].r_addend; 262 break; 263 case R_X86_64_RELATIVE: 264 relocValue = image->text_region.delta + rel[i].r_addend; 265 break; 266 default: 267 dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", 268 type); 269 return B_BAD_DATA; 270 } 271 #ifdef _BOOT_MODE 272 boot_elf64_set_relocation(relocAddr, relocValue); 273 #else 274 if (!is_in_image(image, relocAddr)) { 275 dprintf("arch_elf_relocate_rela: invalid offset %#lx\n", 276 rel[i].r_offset); 277 return B_BAD_ADDRESS; 278 } 279 280 if (type == R_X86_64_PC32) 281 *(Elf32_Addr *)relocAddr = relocValue; 282 else 283 *(Elf64_Addr *)relocAddr = relocValue; 284 #endif 285 } 286 287 return B_OK; 288 } 289 290 291 #endif // (defined(__x86_64__) && !defined(ELF32_COMPAT)) || 292 // (defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF64)) 293