1 /* 2 * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 * 5 * 6 * Copyright 2002, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 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 CHATTY 0 21 22 #ifdef _BOOT_MODE 23 status_t 24 boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, 25 struct Elf32_Rel *rel, int rel_len) 26 #else 27 int 28 arch_elf_relocate_rel(struct elf_image_info *image, 29 struct elf_image_info *resolve_image, struct Elf32_Rel *rel, int rel_len) 30 #endif 31 { 32 // there are no rel entries in PPC elf 33 return B_NO_ERROR; 34 } 35 36 37 static inline void 38 write_word32(addr_t P, Elf32_Word value) 39 { 40 *(Elf32_Word*)P = value; 41 } 42 43 44 static inline void 45 write_word30(addr_t P, Elf32_Word value) 46 { 47 // bits 0:29 48 *(Elf32_Word*)P = (*(Elf32_Word*)P & 0x3) | (value << 2); 49 } 50 51 52 static inline bool 53 write_low24_check(addr_t P, Elf32_Word value) 54 { 55 // bits 6:29 56 if ((value & 0x3f000000) && (~value & 0x3f800000)) 57 return false; 58 *(Elf32_Word*)P = (*(Elf32_Word*)P & 0xfc000003) 59 | ((value & 0x00ffffff) << 2); 60 return true; 61 } 62 63 64 static inline bool 65 write_low14_check(addr_t P, Elf32_Word value) 66 { 67 // bits 16:29 68 if ((value & 0x3fffc000) && (~value & 0x3fffe000)) 69 return false; 70 *(Elf32_Word*)P = (*(Elf32_Word*)P & 0xffff0003) 71 | ((value & 0x00003fff) << 2); 72 return true; 73 } 74 75 76 static inline void 77 write_half16(addr_t P, Elf32_Word value) 78 { 79 // bits 16:29 80 *(Elf32_Half*)P = (Elf32_Half)value; 81 } 82 83 84 static inline bool 85 write_half16_check(addr_t P, Elf32_Word value) 86 { 87 // bits 16:29 88 if ((value & 0xffff0000) && (~value & 0xffff8000)) 89 return false; 90 *(Elf32_Half*)P = (Elf32_Half)value; 91 return true; 92 } 93 94 95 static inline Elf32_Word 96 lo(Elf32_Word value) 97 { 98 return (value & 0xffff); 99 } 100 101 102 static inline Elf32_Word 103 hi(Elf32_Word value) 104 { 105 return ((value >> 16) & 0xffff); 106 } 107 108 109 static inline Elf32_Word 110 ha(Elf32_Word value) 111 { 112 return (((value >> 16) + (value & 0x8000 ? 1 : 0)) & 0xffff); 113 } 114 115 116 #ifdef _BOOT_MODE 117 status_t 118 boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image, 119 struct Elf32_Rela *rel, int rel_len) 120 #else 121 int 122 arch_elf_relocate_rela(struct elf_image_info *image, 123 struct elf_image_info *resolve_image, struct Elf32_Rela *rel, int rel_len) 124 #endif 125 { 126 int i; 127 struct Elf32_Sym *sym; 128 int vlErr; 129 addr_t S = 0; // symbol address 130 addr_t R = 0; // section relative symbol address 131 132 addr_t G = 0; // GOT address 133 addr_t L = 0; // PLT address 134 135 #define P ((addr_t)(image->text_region.delta + rel[i].r_offset)) 136 #define A ((addr_t)rel[i].r_addend) 137 #define B (image->text_region.delta) 138 139 // TODO: Get the GOT address! 140 #define REQUIRE_GOT \ 141 if (G == 0) { \ 142 dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \ 143 return B_ERROR; \ 144 } 145 146 // TODO: Get the PLT address! 147 #define REQUIRE_PLT \ 148 if (L == 0) { \ 149 dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \ 150 return B_ERROR; \ 151 } 152 153 for (i = 0; i * (int)sizeof(struct Elf32_Rela) < rel_len; i++) { 154 #if CHATTY 155 dprintf("looking at rel type %d, offset 0x%lx, sym 0x%lx, addend 0x%lx\n", 156 ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend); 157 #endif 158 switch (ELF32_R_TYPE(rel[i].r_info)) { 159 case R_PPC_SECTOFF: 160 case R_PPC_SECTOFF_LO: 161 case R_PPC_SECTOFF_HI: 162 case R_PPC_SECTOFF_HA: 163 dprintf("arch_elf_relocate_rela(): Getting section relative " 164 "symbol addresses not yet supported!\n"); 165 return B_ERROR; 166 167 case R_PPC_ADDR32: 168 case R_PPC_ADDR24: 169 case R_PPC_ADDR16: 170 case R_PPC_ADDR16_LO: 171 case R_PPC_ADDR16_HI: 172 case R_PPC_ADDR16_HA: 173 case R_PPC_ADDR14: 174 case R_PPC_ADDR14_BRTAKEN: 175 case R_PPC_ADDR14_BRNTAKEN: 176 case R_PPC_REL24: 177 case R_PPC_REL14: 178 case R_PPC_REL14_BRTAKEN: 179 case R_PPC_REL14_BRNTAKEN: 180 case R_PPC_GLOB_DAT: 181 case R_PPC_UADDR32: 182 case R_PPC_UADDR16: 183 case R_PPC_REL32: 184 case R_PPC_SDAREL16: 185 case R_PPC_ADDR30: 186 case R_PPC_JMP_SLOT: 187 sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); 188 189 #ifdef _BOOT_MODE 190 vlErr = boot_elf_resolve_symbol(image, sym, &S); 191 #else 192 vlErr = elf_resolve_symbol(image, sym, resolve_image, &S); 193 #endif 194 if (vlErr < 0) { 195 dprintf("%s(): Failed to relocate " 196 "entry index %d, rel type %d, offset 0x%lx, sym 0x%lx, " 197 "addend 0x%lx\n", __FUNCTION__, i, ELF32_R_TYPE(rel[i].r_info), 198 rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), 199 rel[i].r_addend); 200 return vlErr; 201 } 202 break; 203 } 204 205 switch (ELF32_R_TYPE(rel[i].r_info)) { 206 case R_PPC_NONE: 207 break; 208 209 case R_PPC_COPY: 210 // TODO: Implement! 211 dprintf("arch_elf_relocate_rela(): R_PPC_COPY not yet " 212 "supported!\n"); 213 return B_ERROR; 214 215 case R_PPC_ADDR32: 216 case R_PPC_GLOB_DAT: 217 case R_PPC_UADDR32: 218 write_word32(P, S + A); 219 break; 220 221 case R_PPC_ADDR24: 222 if (write_low24_check(P, (S + A) >> 2)) 223 break; 224 dprintf("R_PPC_ADDR24 overflow\n"); 225 return B_BAD_DATA; 226 227 case R_PPC_ADDR16: 228 case R_PPC_UADDR16: 229 if (write_half16_check(P, S + A)) 230 break; 231 dprintf("R_PPC_ADDR16 overflow\n"); 232 return B_BAD_DATA; 233 234 case R_PPC_ADDR16_LO: 235 write_half16(P, lo(S + A)); 236 break; 237 238 case R_PPC_ADDR16_HI: 239 write_half16(P, hi(S + A)); 240 break; 241 242 case R_PPC_ADDR16_HA: 243 write_half16(P, ha(S + A)); 244 break; 245 246 case R_PPC_ADDR14: 247 case R_PPC_ADDR14_BRTAKEN: 248 case R_PPC_ADDR14_BRNTAKEN: 249 if (write_low14_check(P, (S + A) >> 2)) 250 break; 251 dprintf("R_PPC_ADDR14 overflow\n"); 252 return B_BAD_DATA; 253 254 case R_PPC_REL24: 255 if (write_low24_check(P, (S + A - P) >> 2)) 256 break; 257 dprintf("R_PPC_REL24 overflow: 0x%lx\n", (S + A - P) >> 2); 258 return B_BAD_DATA; 259 260 case R_PPC_REL14: 261 case R_PPC_REL14_BRTAKEN: 262 case R_PPC_REL14_BRNTAKEN: 263 if (write_low14_check(P, (S + A - P) >> 2)) 264 break; 265 dprintf("R_PPC_REL14 overflow\n"); 266 return B_BAD_DATA; 267 268 case R_PPC_GOT16: 269 REQUIRE_GOT; 270 if (write_half16_check(P, G + A)) 271 break; 272 dprintf("R_PPC_GOT16 overflow\n"); 273 return B_BAD_DATA; 274 275 case R_PPC_GOT16_LO: 276 REQUIRE_GOT; 277 write_half16(P, lo(G + A)); 278 break; 279 280 case R_PPC_GOT16_HI: 281 REQUIRE_GOT; 282 write_half16(P, hi(G + A)); 283 break; 284 285 case R_PPC_GOT16_HA: 286 REQUIRE_GOT; 287 write_half16(P, ha(G + A)); 288 break; 289 290 case R_PPC_JMP_SLOT: 291 { 292 // If the relative offset is small enough, we fabricate a 293 // relative branch instruction ("b <addr>"). 294 addr_t jumpOffset = S - P; 295 if ((jumpOffset & 0xfc000000) != 0 296 && (~jumpOffset & 0xfe000000) != 0) { 297 // Offset > 24 bit. 298 // TODO: Implement! 299 // See System V PPC ABI supplement, p. 5-6! 300 dprintf("arch_elf_relocate_rela(): R_PPC_JMP_SLOT: " 301 "Offsets > 24 bit currently not supported!\n"); 302 dprintf("jumpOffset: %p\n", (void*)jumpOffset); 303 return B_ERROR; 304 } else { 305 // Offset <= 24 bit 306 // 0:5 opcode (= 18), 6:29 address, 30 AA, 31 LK 307 // "b" instruction: opcode = 18, AA = 0, LK = 0 308 // address: 24 high-order bits of 26 bit offset 309 *(uint32*)P = 0x48000000 | ((jumpOffset) & 0x03fffffc); 310 } 311 break; 312 } 313 314 case R_PPC_RELATIVE: 315 write_word32(P, B + A); 316 break; 317 318 case R_PPC_LOCAL24PC: 319 // TODO: Implement! 320 // low24* 321 // if (write_low24_check(P, ?) 322 // break; 323 // return B_BAD_DATA; 324 dprintf("arch_elf_relocate_rela(): R_PPC_LOCAL24PC not yet " 325 "supported!\n"); 326 return B_ERROR; 327 328 case R_PPC_REL32: 329 write_word32(P, S + A - P); 330 break; 331 332 case R_PPC_PLTREL24: 333 REQUIRE_PLT; 334 if (write_low24_check(P, (L + A - P) >> 2)) 335 break; 336 dprintf("R_PPC_PLTREL24 overflow\n"); 337 return B_BAD_DATA; 338 339 case R_PPC_PLT32: 340 REQUIRE_PLT; 341 write_word32(P, L + A); 342 break; 343 344 case R_PPC_PLTREL32: 345 REQUIRE_PLT; 346 write_word32(P, L + A - P); 347 break; 348 349 case R_PPC_PLT16_LO: 350 REQUIRE_PLT; 351 write_half16(P, lo(L + A)); 352 break; 353 354 case R_PPC_PLT16_HI: 355 REQUIRE_PLT; 356 write_half16(P, hi(L + A)); 357 break; 358 359 case R_PPC_PLT16_HA: 360 write_half16(P, ha(L + A)); 361 break; 362 363 case R_PPC_SDAREL16: 364 // TODO: Implement! 365 // if (write_half16_check(P, S + A - _SDA_BASE_)) 366 // break; 367 // return B_BAD_DATA; 368 dprintf("arch_elf_relocate_rela(): R_PPC_SDAREL16 not yet " 369 "supported!\n"); 370 return B_ERROR; 371 372 case R_PPC_SECTOFF: 373 if (write_half16_check(P, R + A)) 374 break; 375 dprintf("R_PPC_SECTOFF overflow\n"); 376 return B_BAD_DATA; 377 378 case R_PPC_SECTOFF_LO: 379 write_half16(P, lo(R + A)); 380 break; 381 382 case R_PPC_SECTOFF_HI: 383 write_half16(P, hi(R + A)); 384 break; 385 386 case R_PPC_SECTOFF_HA: 387 write_half16(P, ha(R + A)); 388 break; 389 390 case R_PPC_ADDR30: 391 write_word30(P, (S + A - P) >> 2); 392 break; 393 394 default: 395 dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info)); 396 return B_ERROR; 397 } 398 } 399 400 return B_NO_ERROR; 401 } 402 403