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