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 23status_t 24boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, Elf32_Rel *rel, 25 int rel_len) 26#else 27int 28arch_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 37static inline void 38write_word32(addr_t P, Elf32_Word value) 39{ 40 *(Elf32_Word*)P = value; 41} 42 43 44static inline void 45write_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 52static inline bool 53write_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 64static inline bool 65write_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 76static inline void 77write_half16(addr_t P, Elf32_Word value) 78{ 79 // bits 16:29 80 *(Elf32_Half*)P = (Elf32_Half)value; 81} 82 83 84static inline bool 85write_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 95static inline Elf32_Word 96lo(Elf32_Word value) 97{ 98 return (value & 0xffff); 99} 100 101 102static inline Elf32_Word 103hi(Elf32_Word value) 104{ 105 return ((value >> 16) & 0xffff); 106} 107 108 109static inline Elf32_Word 110ha(Elf32_Word value) 111{ 112 return (((value >> 16) + (value & 0x8000 ? 1 : 0)) & 0xffff); 113} 114 115 116#ifdef _BOOT_MODE 117status_t 118boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image, 119 Elf32_Rela *rel, int rel_len) 120#else 121int 122arch_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; 225dprintf("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; 232dprintf("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; 252dprintf("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; 258dprintf("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; 266dprintf("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; 273dprintf("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"); 303dprintf("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; 337dprintf("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; 376dprintf("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