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