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, Elf32_Rel *rel, 25 int rel_len) 26 #else 27 int 28 arch_elf_relocate_rel(struct elf_image_info *image, 29 struct elf_image_info *resolve_image, 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 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, Elf32_Rela *rel, int rel_len) 124 #endif 125 { 126 int i; 127 Elf32_Sym *sym; 128 int vlErr; 129 130 Elf32_Addr S = 0; // symbol address 131 addr_t R = 0; // section relative symbol address 132 133 addr_t G = 0; // GOT address 134 addr_t L = 0; // PLT address 135 136 #define P ((addr_t)(image->text_region.delta + rel[i].r_offset)) 137 #define A ((addr_t)rel[i].r_addend) 138 #define B (image->text_region.delta) 139 140 // TODO: Get the GOT address! 141 #define REQUIRE_GOT \ 142 if (G == 0) { \ 143 dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \ 144 return B_ERROR; \ 145 } 146 147 // TODO: Get the PLT address! 148 #define REQUIRE_PLT \ 149 if (L == 0) { \ 150 dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \ 151 return B_ERROR; \ 152 } 153 154 for (i = 0; i * (int)sizeof(Elf32_Rela) < rel_len; i++) { 155 #if CHATTY 156 dprintf("looking at rel type %d, offset 0x%lx, sym 0x%lx, addend 0x%lx\n", 157 ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend); 158 #endif 159 switch (ELF32_R_TYPE(rel[i].r_info)) { 160 case R_PPC_SECTOFF: 161 case R_PPC_SECTOFF_LO: 162 case R_PPC_SECTOFF_HI: 163 case R_PPC_SECTOFF_HA: 164 dprintf("arch_elf_relocate_rela(): Getting section relative " 165 "symbol addresses not yet supported!\n"); 166 return B_ERROR; 167 168 case R_PPC_ADDR32: 169 case R_PPC_ADDR24: 170 case R_PPC_ADDR16: 171 case R_PPC_ADDR16_LO: 172 case R_PPC_ADDR16_HI: 173 case R_PPC_ADDR16_HA: 174 case R_PPC_ADDR14: 175 case R_PPC_ADDR14_BRTAKEN: 176 case R_PPC_ADDR14_BRNTAKEN: 177 case R_PPC_REL24: 178 case R_PPC_REL14: 179 case R_PPC_REL14_BRTAKEN: 180 case R_PPC_REL14_BRNTAKEN: 181 case R_PPC_GLOB_DAT: 182 case R_PPC_UADDR32: 183 case R_PPC_UADDR16: 184 case R_PPC_REL32: 185 case R_PPC_SDAREL16: 186 case R_PPC_ADDR30: 187 case R_PPC_JMP_SLOT: 188 sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); 189 190 #ifdef _BOOT_MODE 191 vlErr = boot_elf_resolve_symbol(image, sym, &S); 192 #else 193 vlErr = elf_resolve_symbol(image, sym, resolve_image, &S); 194 #endif 195 if (vlErr < 0) { 196 dprintf("%s(): Failed to relocate " 197 "entry index %d, rel type %d, offset 0x%lx, sym 0x%lx, " 198 "addend 0x%lx\n", __FUNCTION__, i, ELF32_R_TYPE(rel[i].r_info), 199 rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), 200 rel[i].r_addend); 201 return vlErr; 202 } 203 break; 204 } 205 206 switch (ELF32_R_TYPE(rel[i].r_info)) { 207 case R_PPC_NONE: 208 break; 209 210 case R_PPC_COPY: 211 // TODO: Implement! 212 dprintf("arch_elf_relocate_rela(): R_PPC_COPY not yet " 213 "supported!\n"); 214 return B_ERROR; 215 216 case R_PPC_ADDR32: 217 case R_PPC_GLOB_DAT: 218 case R_PPC_UADDR32: 219 write_word32(P, S + A); 220 break; 221 222 case R_PPC_ADDR24: 223 if (write_low24_check(P, (S + A) >> 2)) 224 break; 225 dprintf("R_PPC_ADDR24 overflow\n"); 226 return B_BAD_DATA; 227 228 case R_PPC_ADDR16: 229 case R_PPC_UADDR16: 230 if (write_half16_check(P, S + A)) 231 break; 232 dprintf("R_PPC_ADDR16 overflow\n"); 233 return B_BAD_DATA; 234 235 case R_PPC_ADDR16_LO: 236 write_half16(P, lo(S + A)); 237 break; 238 239 case R_PPC_ADDR16_HI: 240 write_half16(P, hi(S + A)); 241 break; 242 243 case R_PPC_ADDR16_HA: 244 write_half16(P, ha(S + A)); 245 break; 246 247 case R_PPC_ADDR14: 248 case R_PPC_ADDR14_BRTAKEN: 249 case R_PPC_ADDR14_BRNTAKEN: 250 if (write_low14_check(P, (S + A) >> 2)) 251 break; 252 dprintf("R_PPC_ADDR14 overflow\n"); 253 return B_BAD_DATA; 254 255 case R_PPC_REL24: 256 if (write_low24_check(P, (S + A - P) >> 2)) 257 break; 258 dprintf("R_PPC_REL24 overflow: 0x%lx\n", (S + A - P) >> 2); 259 return B_BAD_DATA; 260 261 case R_PPC_REL14: 262 case R_PPC_REL14_BRTAKEN: 263 case R_PPC_REL14_BRNTAKEN: 264 if (write_low14_check(P, (S + A - P) >> 2)) 265 break; 266 dprintf("R_PPC_REL14 overflow\n"); 267 return B_BAD_DATA; 268 269 case R_PPC_GOT16: 270 REQUIRE_GOT; 271 if (write_half16_check(P, G + A)) 272 break; 273 dprintf("R_PPC_GOT16 overflow\n"); 274 return B_BAD_DATA; 275 276 case R_PPC_GOT16_LO: 277 REQUIRE_GOT; 278 write_half16(P, lo(G + A)); 279 break; 280 281 case R_PPC_GOT16_HI: 282 REQUIRE_GOT; 283 write_half16(P, hi(G + A)); 284 break; 285 286 case R_PPC_GOT16_HA: 287 REQUIRE_GOT; 288 write_half16(P, ha(G + A)); 289 break; 290 291 case R_PPC_JMP_SLOT: 292 { 293 // If the relative offset is small enough, we fabricate a 294 // relative branch instruction ("b <addr>"). 295 addr_t jumpOffset = S - P; 296 if ((jumpOffset & 0xfc000000) != 0 297 && (~jumpOffset & 0xfe000000) != 0) { 298 // Offset > 24 bit. 299 // TODO: Implement! 300 // See System V PPC ABI supplement, p. 5-6! 301 dprintf("arch_elf_relocate_rela(): R_PPC_JMP_SLOT: " 302 "Offsets > 24 bit currently not supported!\n"); 303 dprintf("jumpOffset: %p\n", (void*)jumpOffset); 304 return B_ERROR; 305 } else { 306 // Offset <= 24 bit 307 // 0:5 opcode (= 18), 6:29 address, 30 AA, 31 LK 308 // "b" instruction: opcode = 18, AA = 0, LK = 0 309 // address: 24 high-order bits of 26 bit offset 310 *(uint32*)P = 0x48000000 | ((jumpOffset) & 0x03fffffc); 311 } 312 break; 313 } 314 315 case R_PPC_RELATIVE: 316 write_word32(P, B + A); 317 break; 318 319 case R_PPC_LOCAL24PC: 320 // TODO: Implement! 321 // low24* 322 // if (write_low24_check(P, ?) 323 // break; 324 // return B_BAD_DATA; 325 dprintf("arch_elf_relocate_rela(): R_PPC_LOCAL24PC not yet " 326 "supported!\n"); 327 return B_ERROR; 328 329 case R_PPC_REL32: 330 write_word32(P, S + A - P); 331 break; 332 333 case R_PPC_PLTREL24: 334 REQUIRE_PLT; 335 if (write_low24_check(P, (L + A - P) >> 2)) 336 break; 337 dprintf("R_PPC_PLTREL24 overflow\n"); 338 return B_BAD_DATA; 339 340 case R_PPC_PLT32: 341 REQUIRE_PLT; 342 write_word32(P, L + A); 343 break; 344 345 case R_PPC_PLTREL32: 346 REQUIRE_PLT; 347 write_word32(P, L + A - P); 348 break; 349 350 case R_PPC_PLT16_LO: 351 REQUIRE_PLT; 352 write_half16(P, lo(L + A)); 353 break; 354 355 case R_PPC_PLT16_HI: 356 REQUIRE_PLT; 357 write_half16(P, hi(L + A)); 358 break; 359 360 case R_PPC_PLT16_HA: 361 write_half16(P, ha(L + A)); 362 break; 363 364 case R_PPC_SDAREL16: 365 // TODO: Implement! 366 // if (write_half16_check(P, S + A - _SDA_BASE_)) 367 // break; 368 // return B_BAD_DATA; 369 dprintf("arch_elf_relocate_rela(): R_PPC_SDAREL16 not yet " 370 "supported!\n"); 371 return B_ERROR; 372 373 case R_PPC_SECTOFF: 374 if (write_half16_check(P, R + A)) 375 break; 376 dprintf("R_PPC_SECTOFF overflow\n"); 377 return B_BAD_DATA; 378 379 case R_PPC_SECTOFF_LO: 380 write_half16(P, lo(R + A)); 381 break; 382 383 case R_PPC_SECTOFF_HI: 384 write_half16(P, hi(R + A)); 385 break; 386 387 case R_PPC_SECTOFF_HA: 388 write_half16(P, ha(R + A)); 389 break; 390 391 case R_PPC_ADDR30: 392 write_word30(P, (S + A - P) >> 2); 393 break; 394 395 default: 396 dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info)); 397 return B_ERROR; 398 } 399 } 400 401 return B_NO_ERROR; 402 } 403 404