File indexing completed on 2025-05-11 08:24:16
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include <sys/cdefs.h>
0043
0044 #include <errno.h>
0045 #include <inttypes.h>
0046 #include <stdio.h>
0047 #include <sys/types.h>
0048 #include <sys/stat.h>
0049
0050 #include <rtems/rtl/rtl.h>
0051 #include "rtl-bit-alloc.h"
0052 #include "rtl-elf.h"
0053 #include "rtl-error.h"
0054 #include <rtems/rtl/rtl-trace.h>
0055 #include "rtl-unwind.h"
0056 #include "rtl-unwind-dw2.h"
0057
0058 #define ha(x) ((((u_int32_t)(x) & 0x8000) ? \
0059 ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
0060 #define l(x) ((u_int32_t)(x) & 0xffff)
0061
0062
0063
0064
0065 static rtems_rtl_bit_alloc* sdata;
0066
0067 static Elf_Addr
0068 get_sda_base (void)
0069 {
0070 uint32_t sda_base;
0071 __asm__ volatile (" mr %0, 13\n" : "=r" (sda_base));
0072 return sda_base;
0073 }
0074
0075
0076
0077
0078
0079
0080
0081 #define GET_ADDR(_l, _v) \
0082 __asm__ volatile (" lis %0, " #_l "@h\n" \
0083 " ori %0, %0, " #_l "@l\n" : "=r" (_v))
0084
0085 static void*
0086 get_sdata_start (void)
0087 {
0088 #if _ARCH_PPC64
0089 return NULL;
0090 #else
0091 Elf_Addr addr;
0092 GET_ADDR(__SDATA_START__, addr);
0093 return (void*) addr;
0094 #endif
0095 }
0096
0097 #if !_ARCH_PPC64
0098 static size_t
0099 get_sdata_sbss_size (void)
0100 {
0101 Elf_Addr sdata_begin;
0102 Elf_Addr sbss_end;
0103 GET_ADDR(bsp_section_sdata_begin, sdata_begin);
0104 GET_ADDR(bsp_section_sbss_end, sbss_end);
0105 return sbss_end - sdata_begin;
0106 }
0107
0108 static size_t
0109 get_sdata_libdl_size (void)
0110 {
0111 Elf_Addr begin;
0112 Elf_Addr end;
0113 GET_ADDR(bsp_section_sdata_libdl_begin, begin);
0114 GET_ADDR(bsp_section_sdata_libdl_end, end);
0115 return end - begin;
0116 }
0117 #endif
0118
0119 uint32_t
0120 rtems_rtl_elf_section_flags (const rtems_rtl_obj* obj,
0121 const Elf_Shdr* shdr)
0122 {
0123 return 0;
0124 }
0125
0126 uint32_t
0127 rtems_rtl_elf_arch_parse_section (const rtems_rtl_obj* obj,
0128 int section,
0129 const char* name,
0130 const Elf_Shdr* shdr,
0131 const uint32_t flags)
0132 {
0133 #if !_ARCH_PPC64
0134 struct {
0135 const char* label;
0136 size_t len;
0137 } prefix[] = {
0138 #define SEPARATED_PREFIX(_p) { _p, sizeof (_p) - 1 }
0139 SEPARATED_PREFIX (".sdata"),
0140 SEPARATED_PREFIX (".sbss"),
0141 };
0142 const size_t prefixes = sizeof (prefix) / sizeof (prefix[0]);
0143 size_t p;
0144 for (p = 0; p < prefixes; ++p)
0145 {
0146 if (strncmp (name, prefix[p].label, prefix[p].len) == 0)
0147 return flags | RTEMS_RTL_OBJ_SECT_ARCH_ALLOC;
0148 }
0149 #endif
0150 return flags;
0151 }
0152
0153 bool
0154 rtems_rtl_elf_arch_section_alloc (const rtems_rtl_obj* obj,
0155 rtems_rtl_obj_sect* sect)
0156 {
0157 #if _ARCH_PPC64
0158 rtems_rtl_set_error (ENOMEM, ".sdata no supported by ABI");
0159 return false;
0160 #else
0161 if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
0162 printf ("rtl: section: arch: alloc: name=%s size=%zu flags=%08" PRIx32 \
0163 " order=%i link=%d info=%d\n",
0164 sect->name, sect->size, sect->flags, sect->load_order,
0165 sect->link, sect->info);
0166
0167 if (sdata == NULL)
0168 {
0169 sdata = rtems_rtl_bit_alloc_open (get_sdata_start (),
0170 get_sdata_libdl_size (),
0171 sizeof (uint32_t),
0172 get_sdata_sbss_size ());
0173 if (sdata == NULL)
0174 {
0175 rtems_rtl_set_error (ENOMEM, "no memory for sdata allocator");
0176 return false;
0177 }
0178 }
0179
0180 sect->base = rtems_rtl_bit_alloc_balloc (sdata, sect->size);
0181 if (sect->base == NULL)
0182 {
0183 rtems_rtl_set_error (ENOMEM, "no .sdata memory: %s", sect->name);
0184 return false;
0185 }
0186
0187 return true;
0188 #endif
0189 }
0190
0191 bool
0192 rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj,
0193 rtems_rtl_obj_sect* sect)
0194 {
0195 #if !_ARCH_PPC64
0196 if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
0197 printf ("rtl: section: arch: free: name=%s size=%zu\n", sect->name, sect->size);
0198 if (sdata != NULL)
0199 rtems_rtl_bit_alloc_bfree (sdata, sect->base, sect->size);
0200 #endif
0201 return true;
0202 }
0203
0204 bool
0205 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
0206 {
0207 return true;
0208 }
0209
0210 uint32_t rtems_rtl_obj_tramp_alignment (const rtems_rtl_obj* obj)
0211 {
0212 (void) obj;
0213 return sizeof(uint32_t);
0214 }
0215
0216 size_t
0217 rtems_rtl_elf_relocate_tramp_max_size (void)
0218 {
0219
0220
0221
0222 return 4 * 4;
0223 }
0224
0225 static void*
0226 set_veneer (void* trampoline, Elf_Addr target)
0227 {
0228
0229
0230
0231
0232
0233
0234
0235
0236 #if COMPILE_ASM
0237 asm volatile (" lis 12,0x1234\n" \
0238 " ori 12,12,0x5678\n" \
0239 " mtctr 12\n" \
0240 " bctr\n");
0241 #endif
0242 uint32_t* tramp = (uint32_t*) trampoline;
0243 *tramp++ = 0x3d800000 | (target >> 16);
0244 *tramp++ = 0x618c0000 | (target & 0xffff);
0245 *tramp++ = 0x7d8903a6;
0246 *tramp++ = 0x4e800420;
0247 return tramp;
0248 }
0249
0250 static size_t
0251 get_veneer_size (int type)
0252 {
0253 (void) type;
0254 return rtems_rtl_elf_relocate_tramp_max_size ();
0255 }
0256
0257
0258
0259
0260 #define REL_R_OFFSET (0)
0261 #define REL_R_INFO (1)
0262 #define REL_R_ADDEND (2)
0263
0264 static rtems_rtl_elf_rel_status
0265 rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj,
0266 const Elf_Rela* rela,
0267 const rtems_rtl_obj_sect* sect,
0268 const char* symname,
0269 const Elf_Byte syminfo,
0270 const Elf_Word symvalue,
0271 const bool parsing)
0272 {
0273 Elf_Addr* where;
0274 Elf_Word tmp;
0275 uint32_t mask = 0;
0276 uint32_t bits = 0;
0277 bool needs_tramp = false;
0278
0279 where = (Elf_Addr *)(sect->base + rela->r_offset);
0280 switch (ELF_R_TYPE(rela->r_info)) {
0281 case R_TYPE(NONE):
0282 break;
0283
0284 case R_TYPE(32):
0285
0286
0287
0288 if (!parsing) {
0289 *where = symvalue + rela->r_addend;
0290 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0291 printf ("rtl: ADDR32 %p @ %p in %s\n",
0292 (void *)*(where), where, rtems_rtl_obj_oname (obj));
0293 }
0294 break;
0295
0296 case R_TYPE(14):
0297
0298
0299
0300 case R_TYPE(24):
0301
0302
0303
0304 if (ELF_R_TYPE(rela->r_info) == R_TYPE(14)) {
0305 bits = 14;
0306 mask = 0xfffc;
0307 } else {
0308 bits = 24;
0309 mask = 0x3fffffc;
0310 }
0311
0312 if (parsing && sect->base == 0) {
0313 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0314 printf ("rtl: ADDR14/ADDR24 tramp cache\n");
0315 return rtems_rtl_elf_rel_tramp_cache;
0316 }
0317
0318 tmp = (symvalue + rela->r_addend) >> 2;
0319 if (tmp > ((1<<bits) - 1 )) {
0320 Elf_Word tramp_addr;
0321 size_t tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
0322 if (parsing) {
0323 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0324 printf ("rtl: ADDR14/ADDR24 tramp add\n");
0325 return rtems_rtl_elf_rel_tramp_add;
0326 }
0327 if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
0328 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0329 printf ("rtl: ADDR14/ADDR24 no tramp slot: %s\n", rtems_rtl_obj_oname (obj));
0330 rtems_rtl_set_error (ENOMEM, "%s: tramp: no slot: ADDR14/ADDR24", sect->name);
0331 return rtems_rtl_elf_rel_failure;
0332 }
0333 needs_tramp = true;
0334 tramp_addr = (Elf_Addr) obj->tramp_brk;
0335 obj->tramp_brk = set_veneer(obj->tramp_brk,
0336 symvalue + rela->r_addend);
0337 tmp = *where;
0338 tmp &= ~mask;
0339 tmp |= (tramp_addr + rela->r_addend) & mask;
0340 }
0341 else {
0342 tmp = *where;
0343 tmp &= ~mask;
0344 tmp |= (symvalue + rela->r_addend) & mask;
0345 }
0346
0347 if (!parsing) {
0348 *where = tmp;
0349 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0350 printf ("rtl: ADDR14/ADDR24%s %p @ %p in %s\n",
0351 needs_tramp ? "(tramp)" : "",
0352 (void *)*where, where, rtems_rtl_obj_oname (obj));
0353 }
0354 break;
0355
0356 case R_TYPE(16_HA):
0357 case R_TYPE(TPREL16_HA):
0358
0359
0360
0361
0362 if (!parsing) {
0363 tmp = symvalue + rela->r_addend;
0364 *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff);
0365 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0366 printf ("rtl: %s16_HA %p @ %p in %s\n",
0367 ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_HA) ? "TPREL" : "",
0368 (void *)*(where), where, rtems_rtl_obj_oname (obj));
0369 }
0370 break;
0371
0372 case R_TYPE(16_HI):
0373 case R_TYPE(TPREL16_HI):
0374
0375
0376
0377
0378 if (!parsing) {
0379 *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff;
0380 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0381 printf ("rtl: %s16_HI %p @ %p in %s\n",
0382 ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_HI) ? "TPREL" : "",
0383 (void *)*where, where, rtems_rtl_obj_oname (obj));
0384 }
0385 break;
0386
0387 case R_TYPE(16_LO):
0388 case R_TYPE(TPREL16_LO):
0389
0390
0391
0392
0393 if (!parsing) {
0394 *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff;
0395 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0396 printf ("rtl: %s16_LO %p @ %p in %s\n",
0397 ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_LO) ? "TPREL" : "",
0398 (void *)*where, where, rtems_rtl_obj_oname (obj));
0399 }
0400 break;
0401
0402 case R_TYPE(REL14):
0403
0404
0405
0406 case R_TYPE(REL24):
0407
0408
0409
0410 if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL24)) {
0411 mask = 0x3fffffc;
0412 bits = 24;
0413 }
0414 else if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL14)) {
0415 mask = 0xfffc;
0416 bits = 14;
0417 }
0418
0419 if (parsing && sect->base == 0) {
0420 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0421 printf ("rtl: REL24/REL14 tramp cache\n");
0422 return rtems_rtl_elf_rel_tramp_cache;
0423 }
0424
0425 tmp =((int) (symvalue + rela->r_addend - (Elf_Addr)where)) >> 2;
0426 if (((Elf_Sword)tmp > ((1<<(bits-1)) - 1)) ||
0427 ((Elf_Sword)tmp < -(1<<(bits-1)))) {
0428 Elf_Word tramp_addr;
0429 size_t tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
0430 if (parsing) {
0431 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0432 printf ("rtl: REL24/REL14 tramp add\n");
0433 return rtems_rtl_elf_rel_tramp_add;
0434 }
0435 if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
0436 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0437 printf ("rtl: REL24/REL14 no tramp slot: %s\n", rtems_rtl_obj_oname (obj));
0438 rtems_rtl_set_error (ENOMEM, "%s: tramp: no slot: REL24/REL14", sect->name);
0439 return rtems_rtl_elf_rel_failure;
0440 }
0441 needs_tramp = true;
0442 tramp_addr = (Elf_Addr) obj->tramp_brk;
0443 obj->tramp_brk = set_veneer(obj->tramp_brk,
0444 symvalue + rela->r_addend);
0445 tmp = *where;
0446 tmp &= ~mask;
0447 tmp |= (tramp_addr + rela->r_addend - (Elf_Addr)where) & mask;
0448 }
0449 else
0450 {
0451 tmp = *where;
0452 tmp &= ~mask;
0453 tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask;
0454 }
0455
0456 if (!parsing) {
0457 *where = tmp;
0458 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0459 printf ("rtl: REL24/REL14%s %p @ %p in %s\n",
0460 needs_tramp ? "(tramp)" : "",
0461 (void *)*where, where, rtems_rtl_obj_oname (obj));
0462 }
0463 break;
0464
0465 case R_TYPE(REL32):
0466
0467
0468
0469 if (!parsing) {
0470 *where = symvalue + rela->r_addend - (Elf_Addr)where;
0471 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0472 printf ("rtl: REL32 %p @ %p in %s\n",
0473 (void *)*where, where, rtems_rtl_obj_oname (obj));
0474 }
0475 break;
0476
0477 case R_TYPE(SDAREL16):
0478
0479
0480
0481
0482 if (!parsing) {
0483 Elf_Addr sda_base = get_sda_base ();
0484 mask = 0xffff;
0485 tmp = *((Elf32_Half*) where);
0486 tmp &= ~mask;
0487 tmp |= (symvalue + rela->r_addend - sda_base) & mask;
0488 *((Elf32_Half*) where) = tmp;
0489 if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0490 printf ("rtl: SDAREL16 %p @ %p in %s\n",
0491 (void *) (uintptr_t) *((Elf32_Half*) where),
0492 where, rtems_rtl_obj_oname (obj));
0493 }
0494 break;
0495
0496 default:
0497 printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p, "
0498 "contents = %p\n",
0499 ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info),
0500 (void *)rela->r_offset, (void *)*where);
0501 rtems_rtl_set_error (EINVAL,
0502 "%s: Unsupported relocation type %" PRId32
0503 " in non-PLT relocations",
0504 sect->name, (uint32_t) ELF_R_TYPE(rela->r_info));
0505 return rtems_rtl_elf_rel_failure;
0506 }
0507 return rtems_rtl_elf_rel_no_error;
0508 }
0509
0510 rtems_rtl_elf_rel_status
0511 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj* obj,
0512 const Elf_Rela* rela,
0513 const rtems_rtl_obj_sect* sect,
0514 const char* symname,
0515 const Elf_Byte syminfo,
0516 const Elf_Word symvalue)
0517 {
0518 return rtems_rtl_elf_reloc_rela (obj,
0519 rela,
0520 sect,
0521 symname,
0522 syminfo,
0523 symvalue,
0524 true);
0525 }
0526
0527 rtems_rtl_elf_rel_status
0528 rtems_rtl_elf_relocate_rela (rtems_rtl_obj* obj,
0529 const Elf_Rela* rela,
0530 const rtems_rtl_obj_sect* sect,
0531 const char* symname,
0532 const Elf_Byte syminfo,
0533 const Elf_Word symvalue)
0534 {
0535 return rtems_rtl_elf_reloc_rela (obj,
0536 rela,
0537 sect,
0538 symname,
0539 syminfo,
0540 symvalue,
0541 false);
0542 }
0543
0544 rtems_rtl_elf_rel_status
0545 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj* obj,
0546 const Elf_Rel* rel,
0547 const rtems_rtl_obj_sect* sect,
0548 const char* symname,
0549 const Elf_Byte syminfo,
0550 const Elf_Word symvalue)
0551 {
0552 (void) obj;
0553 (void) rel;
0554 (void) sect;
0555 (void) symname;
0556 (void) syminfo;
0557 (void) symvalue;
0558 rtems_rtl_set_error (EINVAL, "rel type record not supported");
0559 return rtems_rtl_elf_rel_failure;
0560 }
0561
0562 rtems_rtl_elf_rel_status
0563 rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj,
0564 const Elf_Rel* rel,
0565 const rtems_rtl_obj_sect* sect,
0566 const char* symname,
0567 const Elf_Byte syminfo,
0568 const Elf_Word symvalue)
0569 {
0570 (void) obj;
0571 (void) rel;
0572 (void) sect;
0573 (void) symname;
0574 (void) syminfo;
0575 (void) symvalue;
0576 rtems_rtl_set_error (EINVAL, "rel type record not supported");
0577 return rtems_rtl_elf_rel_failure;
0578 }
0579
0580 bool
0581 rtems_rtl_elf_unwind_parse (const rtems_rtl_obj* obj,
0582 const char* name,
0583 uint32_t flags)
0584 {
0585 return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
0586 }
0587
0588 bool
0589 rtems_rtl_elf_unwind_register (rtems_rtl_obj* obj)
0590 {
0591 return rtems_rtl_elf_unwind_dw2_register (obj);
0592 }
0593
0594 bool
0595 rtems_rtl_elf_unwind_deregister (rtems_rtl_obj* obj)
0596 {
0597 return rtems_rtl_elf_unwind_dw2_deregister (obj);
0598 }