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