bool rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name) { const char* pname; rtems_rtl_data_t* rtl; /* * Parse the name. The object descriptor will have the archive name and/or * object name fields filled in. A find of the file will result in the file * name (fname) field pointing to the actual file if present on the file * system. */ if (!rtems_rtl_obj_parse_name (obj, name)) return false; /* * If the archive field (aname) is set we use that name else we use the * object field (oname). If selected name is absolute we just point the aname * field to the fname field to that name. If the field is relative we search * the paths set in the RTL for the file. */ if (rtems_rtl_obj_aname_valid (obj)) pname = rtems_rtl_obj_aname (obj); else pname = rtems_rtl_obj_oname (obj); rtl = rtems_rtl_lock (); if (!rtems_rtl_find_file (pname, rtl->paths, &obj->fname, &obj->fsize)) { rtems_rtl_set_error (ENOENT, "file not found"); rtems_rtl_unlock (); return false; } rtems_rtl_unlock (); return true; }
/* * 1. _gp_disp symbol are not considered in this file. * 2. There is a local/external column; * local corresponds to (STB_LOCAL & STT_SECTION) and * all others are external. Because if the type of a * symbol is STT_SECTION, it must be STB_LOCAL. Thus * just consider symtype here. */ bool rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, const Elf_Rel* rel, const rtems_rtl_obj_sect_t* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue) { Elf_Addr *where; Elf_Word tmp; Elf_Word addend = (Elf_Word)0; Elf_Word local = 0; uint32_t t; static Elf_Addr *where_hi16; static Elf_Addr ahl; where = (Elf_Addr *)(sect->base + rel->r_offset); addend = *where; if (syminfo == STT_SECTION) local = 1; switch (ELF_R_TYPE(rel->r_info)) { case R_TYPE(NONE): break; case R_TYPE(16): tmp = addend & 0xffff; if ((tmp & 0x8000) == 0x8000) tmp |= 0xffff0000; /* Sign extend */ tmp = symvalue + (int)tmp; if ((tmp & 0xffff0000) != 0) { printf("R_MIPS_16 Overflow\n"); return false; } *where = (tmp & 0xffff) | (*where & 0xffff0000); if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: R_MIPS_16 %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(32): tmp = symvalue + addend; if (addend != tmp) *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: R_MIPS_32 %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(26): addend &= 0x03ffffff; addend <<= 2; if (local == 1) { /* STB_LOCAL and STT_SECTION */ tmp = symvalue + (((Elf_Addr)where & 0xf0000000) | addend); tmp >>= 2; } else { /* external */
bool rtems_rtl_unresolved_add (rtems_rtl_obj_t* obj, const uint16_t flags, const char* name, const uint16_t sect, const rtems_rtl_word_t* rel) { rtems_rtl_unresolved_t* unresolved; rtems_chain_node* node; rtems_rtl_unresolv_block_t* block; rtems_rtl_unresolv_rec_t* rec; int name_index; size_t name_recs; if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) printf ("rtl: unresolv: add: %s(s:%d) -> %s\n", rtems_rtl_obj_oname (obj), sect, name); unresolved = rtems_rtl_unresolved (); if (!unresolved) return false; /* * Find the first block with a spare record. */ node = rtems_chain_first (&unresolved->blocks); block = NULL; while (!rtems_chain_is_tail (&unresolved->blocks, node)) { block = (rtems_rtl_unresolv_block_t*) node; if (block->recs < unresolved->block_recs) break; block = NULL; node = rtems_chain_next (node); } /* * No blocks with any spare records, allocate a new block. */ if (!block) { block = rtems_rtl_unresolved_block_alloc (unresolved); if (!block) return false; } name_index = rtems_rtl_unresolved_find_name (unresolved, name, true); name_recs = rtems_rtl_unresolved_name_recs (name); /* * An index less than 0 means the name is present and "0 - index" is the next * index to use. */ if (name_index < 0) { rtems_rtl_unresolv_block_t* name_block = block; /* * Is there enough room to fit the name ? It not add a new block. */ if (name_recs > (unresolved->block_recs - block->recs)) { name_block = rtems_rtl_unresolved_block_alloc (unresolved); if (!name_block) return false; } rec = rtems_rtl_unresolved_rec_first_free (name_block); rec->type = rtems_rtl_unresolved_name; rec->rec.name.refs = 1; rec->rec.name.length = strlen (name) + 1; memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length + 1); block->recs += name_recs; name_index = 0 - name_index; /* * If the name block is the reloc block and it is full allocate a new * block for the relocation record. */ if ((block == name_block) && (block->recs >= unresolved->block_recs)) { block = rtems_rtl_unresolved_block_alloc (unresolved); if (!block) return false; } } rec = rtems_rtl_unresolved_rec_first_free (block); rec->type = rtems_rtl_unresolved_reloc; rec->rec.reloc.obj = obj; rec->rec.reloc.flags = flags; rec->rec.reloc.name = name_index; rec->rec.reloc.sect = sect; rec->rec.reloc.rel[0] = rel[0]; rec->rec.reloc.rel[1] = rel[1]; rec->rec.reloc.rel[2] = rel[2]; ++block->recs; return true; }
bool rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, const Elf_Rela* rela, const rtems_rtl_obj_sect_t* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue) { Elf_Addr* where; Elf_Word tmp; uint32_t mask = 0; uint32_t bits = 0; where = (Elf_Addr *)(sect->base + rela->r_offset); switch (ELF_R_TYPE(rela->r_info)) { case R_TYPE(NONE): break; case R_TYPE(32): /* * value:1; Field: word32; Expression: S + A */ *where = symvalue + rela->r_addend; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: ADDR32 %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(14): /* * value:7; Field: low14*; Expression: (S + A) >> 2 */ case R_TYPE(24): /* * value:2; Field: low24*; Expression: (S + A) >> 2 */ if (ELF_R_TYPE(rela->r_info) == R_TYPE(14)) { bits = 14; mask = 0xfffc; } else { bits = 24; mask = 0x3fffffc; } tmp = (symvalue + rela->r_addend) >> 2; if (tmp > ((1<<bits) - 1 )) { printf("Overflow ADDR14/ADDR24\n"); return false; } tmp = *where; tmp &= ~mask; tmp |= (symvalue + rela->r_addend) & mask; *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: ADDR14/ADDR24 %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(16_HA): /* * value:6; Field:half16; Expression: #ha(S+A) */ tmp = symvalue + rela->r_addend; *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff); if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: 16_HA %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(16_HI): /* * value:5; Field:half16; Expression: #hi(S+A) */ *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: 16_HI %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(16_LO): /* * value:4; Field:half16; Expression: #lo(S+A) */ *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: 16_LO %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(REL14): /* * value:11; Field:low14*; Expression:(S+A-P)>>2 */ case R_TYPE(REL24): /* * value:10; Field:low24*; Expression:(S+A-P)>>2 */ if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL24)) { mask = 0x3fffffc; bits = 24; } else if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL14)) { mask = 0xfffc; bits = 14; } tmp =((int) (symvalue + rela->r_addend - (Elf_Addr)where)) >> 2; if (((Elf_Sword)tmp > ((1<<(bits-1)) - 1)) || ((Elf_Sword)tmp < -(1<<(bits-1)))) { printf("Overflow REL14/REL24\n"); return false; } tmp = *where; tmp &= ~mask; tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask; *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: REL24/REL14 %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(REL32): /* * value:26; Field:word32*; Expression:S+A-P */ *where = symvalue + rela->r_addend - (Elf_Addr)where; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: REL32 %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; default: printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " "contents = %p\n", ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info), (void *)rela->r_offset, (void *)*where); rtems_rtl_set_error (EINVAL, "%s: Unsupported relocation type %ld " "in non-PLT relocations", sect->name, (uint32_t) ELF_R_TYPE(rela->r_info)); return false; } return true; }
bool rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, const Elf_Rel* rel, const rtems_rtl_obj_sect_t* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue) { Elf_Addr target = 0; Elf_Addr* where; Elf_Addr tmp; where = (Elf_Addr *)(sect->base + rel->r_offset); switch (ELF_R_TYPE(rel->r_info)) { case R_TYPE(NONE): break; case R_TYPE(PC32): target = (Elf_Addr) symvalue; *where += target - (Elf_Addr)where; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: reloc PC32 in %s --> %p (%p @ %p) in %s\n", sect->name, (void*) symvalue, (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(GOT32): case R_TYPE(32): case R_TYPE(GLOB_DAT): target = (Elf_Addr) symvalue; tmp = target + *where; if (*where != tmp) *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: reloc 32/GLOB_DAT in %s --> %p @ %p in %s\n", sect->name, (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(RELATIVE): *where += (Elf_Addr)sect->base; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: reloc RELATIVE in %s --> %p @ %p\n", rtems_rtl_obj_oname (obj), (void *)*where, where); break; case R_TYPE(COPY): printf ("rtl: reloc COPY (please report)\n"); break; default: printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " "contents = %p\n", ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), (void *)rel->r_offset, (void *)*where); rtems_rtl_set_error (EINVAL, "%s: Unsupported relocation type %ld " "in non-PLT relocations", sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); return false; } return true; }
/** * Object printer. */ static bool rtems_rtl_obj_printer (rtems_rtl_obj_print_t* print, rtems_rtl_obj_t* obj) { char flags_str[33]; /* * Skip the base module unless asked to show it. */ if (!print->base && (obj == print->rtl->base)) return true; if (print->oname) { printf ("%-*cobject name : %s\n", print->indent, ' ', rtems_rtl_obj_oname (obj)); } if (print->names) { printf ("%-*cfile name : %s\n", print->indent, ' ', rtems_rtl_obj_fname (obj)); printf ("%-*carchive name : %s\n", print->indent, ' ', rtems_rtl_obj_aname (obj)); strcpy (flags_str, "--"); if (obj->flags & RTEMS_RTL_OBJ_LOCKED) flags_str[0] = 'L'; if (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) flags_str[1] = 'U'; printf ("%-*cflags : %s\n", print->indent, ' ', flags_str); printf ("%-*cfile offset : %" PRIdoff_t "\n", print->indent, ' ', obj->ooffset); printf ("%-*cfile size : %zi\n", print->indent, ' ', obj->fsize); } if (print->memory_map) { printf ("%-*cexec size : %zi\n", print->indent, ' ', obj->exec_size); printf ("%-*ctext base : %p (%zi)\n", print->indent, ' ', obj->text_base, rtems_rtl_delta_voids (obj->const_base, obj->text_base)); printf ("%-*cconst base : %p (%zi)\n", print->indent, ' ', obj->const_base, rtems_rtl_delta_voids (obj->data_base, obj->const_base)); printf ("%-*cdata base : %p (%zi)\n", print->indent, ' ', obj->data_base, rtems_rtl_delta_voids (obj->bss_base, obj->data_base)); printf ("%-*cbss base : %p (%zi)\n", print->indent, ' ', obj->bss_base, obj->bss_size); } printf ("%-*cunresolved : %lu\n", print->indent, ' ', obj->unresolved); printf ("%-*csymbols : %zi\n", print->indent, ' ', obj->global_syms); printf ("%-*csymbol memory : %zi\n", print->indent, ' ', obj->global_size); if (print->symbols) { int max_len = 0; int s; for (s = 0; s < obj->global_syms; ++s) { int len = strlen (obj->global_table[s].name); if (len > max_len) max_len = len; } for (s = 0; s < obj->global_syms; ++s) printf ("%-*c%-*s = %p\n", print->indent + 2, ' ', max_len, obj->global_table[s].name, obj->global_table[s].value); } printf ("\n"); return true; }