static BOOL DLSYM_lookup_symtab(const char *sym_name, struct Elf32_Sym *symtab, Elf32_Word symnum, Elf32_Addr *sym_value, BOOL require_local_binding) { Elf32_Addr sym_idx; #if LOADER_DEBUG if (debugging_on) DLIF_trace("DLSYM_lookup_symtab, sym to find : %s\n", sym_name); #endif for (sym_idx = 0; sym_idx < symnum; sym_idx++) { #if LOADER_DEBUG if (debugging_on) DLIF_trace("\tPotential symbol match : %s\n", (char*)symtab[sym_idx].st_name); #endif if ((symtab[sym_idx].st_shndx != SHN_UNDEF) && ((require_local_binding && (ELF32_ST_BIND(symtab[sym_idx].st_info) == STB_LOCAL)) || (!require_local_binding && (ELF32_ST_BIND(symtab[sym_idx].st_info) != STB_LOCAL))) && !strcmp(sym_name,(char*)(symtab[sym_idx].st_name))) { if (sym_value) *sym_value = symtab[sym_idx].st_value; return TRUE; } } if (sym_value) *sym_value = 0; return FALSE; }
BOOL DLSYM_canonical_lookup(DLOAD_HANDLE handle, int sym_index, DLIMP_Dynamic_Module *dyn_module, Elf32_Addr *sym_value) { /*------------------------------------------------------------------------*/ /* Lookup the symbol table to get the symbol characteristics. */ /*------------------------------------------------------------------------*/ struct Elf32_Sym *sym = &dyn_module->symtab[sym_index]; int32_t st_bind = ELF32_ST_BIND(sym->st_info); int32_t st_vis = ELF32_ST_VISIBILITY(sym->st_other); BOOL is_def = (sym->st_shndx != SHN_UNDEF && (sym->st_shndx < SHN_LORESERVE || sym->st_shndx == SHN_ABS || sym->st_shndx == SHN_COMMON || sym->st_shndx == SHN_XINDEX)); const char *sym_name = (char *)sym->st_name; #if LOADER_DEBUG if (debugging_on) DLIF_trace("DLSYM_canonical_lookup: %d, %s\n", sym_index, sym_name); #endif /*------------------------------------------------------------------------*/ /* Local symbols and symbol definitions that cannot be pre-empted */ /* are resolved by the definition in the same module. */ /*------------------------------------------------------------------------*/ if (st_bind == STB_LOCAL || st_vis != STV_DEFAULT) { /*---------------------------------------------------------------------*/ /* If it is a local symbol or non-local that cannot be preempted, */ /* the definition should be found in the same module. If we don't */ /* find the definition it is an error. */ /*---------------------------------------------------------------------*/ if (!is_def) { DLIF_error(DLET_SYMBOL, "Local/non-imported symbol %s definition is not found " "in module %s!\n", sym_name, dyn_module->name); return FALSE; } else { if (sym_value) *sym_value = sym->st_value; return TRUE; } } /*------------------------------------------------------------------------*/ /* Else we have either pre-emptable defintion or undef symbol. We need */ /* to do global look up. */ /*------------------------------------------------------------------------*/ else { return DLSYM_global_lookup(handle, sym_name, dyn_module->loaded_module, sym_value); } }
void DLSYM_copy_globals(DLIMP_Dynamic_Module *dyn_module) { Elf32_Word i, global_index, global_symnum; DLIMP_Loaded_Module *module = dyn_module->loaded_module; #if LOADER_DEBUG if (debugging_on) DLIF_trace("DLSYM_copy_globals:\n"); #endif /*------------------------------------------------------------------------*/ /* The dynamic symbol table is sorted so that the local symbols come */ /* before the global symbols. gsymtab_offset points to the address where */ /* the first global symbol starts. Only the global symbols need to be */ /* copied into the persistent info. */ /*------------------------------------------------------------------------*/ global_index = dyn_module->gsymtab_offset / sizeof(struct Elf32_Sym); global_symnum = dyn_module->symnum - global_index; /*------------------------------------------------------------------------*/ /* Create space for the new global symbol table. */ /*------------------------------------------------------------------------*/ if (module->gsymtab) DLIF_free(module->gsymtab); module->gsymtab = DLIF_malloc(sizeof(struct Elf32_Sym) * global_symnum); module->gsymnum = global_symnum; if (module->gsymtab) memcpy(module->gsymtab, &dyn_module->symtab[global_index], sizeof(struct Elf32_Sym) * global_symnum); /*------------------------------------------------------------------------*/ /* Copy the string table part that contains the global symbol names. */ /*------------------------------------------------------------------------*/ if (module->gstrtab) DLIF_free(module->gstrtab); module->gstrsz = dyn_module->strsz - dyn_module->gstrtab_offset; module->gstrtab = DLIF_malloc(module->gstrsz); if (module->gstrtab) memcpy(module->gstrtab, dyn_module->strtab + dyn_module->gstrtab_offset, module->gstrsz); /*------------------------------------------------------------------------*/ /* Update the symbol names of the global symbol entries to point to */ /* the symbol names in the string table. */ /* NOTE: Note that we don't set the offset into the string table. We */ /* instead set the full address so that the st_name field can be accessed */ /* as char *. */ /*------------------------------------------------------------------------*/ for (i = 0; i < global_symnum; i++) { Elf32_Word old_offset = dyn_module->symtab[i + global_index].st_name - (Elf32_Addr) dyn_module->strtab; Elf32_Word new_offset = old_offset - dyn_module->gstrtab_offset; if(module->gsymtab) { struct Elf32_Sym *sym = &((struct Elf32_Sym*)(module->gsymtab))[i]; sym->st_name = new_offset + (Elf32_Addr)module->gstrtab; } #if LOADER_DEBUG if (debugging_on) DLIF_trace("Copying symbol: %s\n", (char *) dyn_module->symtab[i + global_index].st_name); #endif } }
BOOL DLSYM_global_lookup(DLOAD_HANDLE handle, const char *sym_name, DLIMP_Loaded_Module *loaded_module, Elf32_Addr *sym_value) { int i = 0; loaded_module_ptr_Queue_Node* node; LOADER_OBJECT *dHandle = (LOADER_OBJECT *)handle; #if LOADER_DEBUG if (debugging_on) DLIF_trace("DLSYM_global_lookup: %s\n", sym_name); #endif /*------------------------------------------------------------------------*/ /* We will choose a different lookup algorithm based on what kind of */ /* platform we are supporting. In the Braveheart case, the global symbol */ /* lookup algorithm searches the base image first, followed by the */ /* explicit children of the specified Module. */ /*------------------------------------------------------------------------*/ if (loaded_module->direct_dependent_only) { int* child_handle = (int*)(loaded_module->dependencies.buf); /*---------------------------------------------------------------------*/ /* Spin through list of this Module's dependencies (anything on its */ /* DT_NEEDED list), searching through each dependent's symbol table */ /* to find the symbol we are after. */ /*---------------------------------------------------------------------*/ for (i = 0; i < loaded_module->dependencies.size; i++) { for (node = dHandle->DLIMP_loaded_objects.front_ptr; node->value->file_handle != child_handle[i]; node=node->next_ptr); /*------------------------------------------------------------------*/ /* Return true if we find the symbol. */ /*------------------------------------------------------------------*/ if (DLSYM_lookup_global_symtab(sym_name, node->value->gsymtab, node->value->gsymnum, sym_value)) return TRUE; } } /*------------------------------------------------------------------------*/ /* In the LINUX model, we will use a breadth-first global symbol lookup */ /* algorithm. First, the application's global symbol table is searched, */ /* followed by its children, followed by their children, and so on. */ /* It is up to the client of this module to set the application handle. */ /*------------------------------------------------------------------------*/ else { if (breadth_first_lookup(handle, sym_name, DLIMP_application_handle, sym_value)) return TRUE; } /*------------------------------------------------------------------------*/ /* If we got this far, then symbol was not found. */ /*------------------------------------------------------------------------*/ DLIF_error(DLET_SYMBOL, "Could not resolve symbol %s!\n", sym_name); return FALSE; }
static void write_reloc_r(uint8_t* buffered_segment, uint32_t segment_offset, int r_type, uint32_t r) { uint32_t* rel_field_ptr = (uint32_t*)(buffered_segment + segment_offset); #if LOADER_DEBUG /*------------------------------------------------------------------------*/ /* Print some details about the relocation we are about to process. */ /*------------------------------------------------------------------------*/ if(debugging_on) { DLIF_trace("RWRT: segment_offset: %d\n", segment_offset); DLIF_trace("RWRT: buffered_segment: 0x%x\n", (uint32_t)buffered_segment); DLIF_trace("RWRT: rel_field_ptr: 0x%x\n", (uint32_t)rel_field_ptr); DLIF_trace("RWRT: result: 0x%x\n", r); } #endif /*------------------------------------------------------------------------*/ /* Given the relocation type, carry out relocation into a 4 byte packet */ /* within the buffered segment. */ /*------------------------------------------------------------------------*/ switch(r_type) { case R_C6000_ABS32: *rel_field_ptr = r; break; case R_C6000_PREL31: *rel_field_ptr = (*rel_field_ptr & ~MASK(30,0)) | r; break; case R_C6000_ABS16: *((uint16_t*)(buffered_segment + segment_offset)) = r; break; case R_C6000_ABS8: *((uint8_t*)(buffered_segment + segment_offset)) = r; break; case R_C6000_PCR_S21: *rel_field_ptr = (*rel_field_ptr & ~MASK(21,7)) | (r << 7); break; case R_C6000_PCR_S12: *rel_field_ptr = (*rel_field_ptr & ~MASK(12,16)) | (r << 16); break; case R_C6000_PCR_S10: *rel_field_ptr = (*rel_field_ptr & ~MASK(10,13)) | (r << 13); break; case R_C6000_PCR_S7: *rel_field_ptr = (*rel_field_ptr & ~MASK(7,16)) | (r << 16); break; case R_C6000_ABS_S16: *rel_field_ptr = (*rel_field_ptr & ~MASK(16,7)) | (r << 7); break; case R_C6000_ABS_L16: *rel_field_ptr = (*rel_field_ptr & ~MASK(16,7)) | (r << 7); break; case R_C6000_ABS_H16: *rel_field_ptr = (*rel_field_ptr & ~MASK(16,7)) | (r << 7); break; case R_C6000_SBR_U15_B: *rel_field_ptr = (*rel_field_ptr & ~MASK(15,8)) | (r << 8); break; case R_C6000_SBR_U15_H: *rel_field_ptr = (*rel_field_ptr & ~MASK(15,8)) | (r << 8); break; case R_C6000_SBR_U15_W: case R_C6000_DSBT_INDEX: *rel_field_ptr = (*rel_field_ptr & ~MASK(15,8)) | (r << 8); break; case R_C6000_SBR_S16: case R_C6000_SBR_L16_B: case R_C6000_SBR_L16_H: case R_C6000_SBR_L16_W: case R_C6000_SBR_H16_B: case R_C6000_SBR_H16_H: case R_C6000_SBR_H16_W: *rel_field_ptr = (*rel_field_ptr & ~MASK(16,7)) | (r << 7); break; /*---------------------------------------------------------------------*/ /* Linux "import-as-own" copy relocations are not yet supported. */ /*---------------------------------------------------------------------*/ case R_C6000_COPY: default: DLIF_error(DLET_RELOC, "write_reloc_r called with invalid relocation type!\n"); } #if LOADER_DEBUG if (debugging_on) DLIF_trace("reloc_field 0x%x\n", *rel_field_ptr); #endif }
static void reloc_do(C60_RELOC_TYPE r_type, uint32_t segment_vaddr, uint8_t *segment_buffer, uint32_t addend, uint32_t symval, uint32_t spc, int wrong_endian, uint32_t base_pointer, int32_t dsbt_index) { int32_t reloc_value = 0; #if LOADER_DEBUG || LOADER_PROFILE /*------------------------------------------------------------------------*/ /* In debug mode, keep a count of the number of relocations processed. */ /* In profile mode, start the clock on a given relocation. */ /*------------------------------------------------------------------------*/ int start_time = 0; if (debugging_on || profiling_on) { DLREL_relocations++; if (profiling_on) start_time = clock(); } #endif /*------------------------------------------------------------------------*/ /* Calculate the relocation value according to the rules associated with */ /* the given relocation type. */ /*------------------------------------------------------------------------*/ switch(r_type) { /*---------------------------------------------------------------------*/ /* Straight-Up Address relocations (address references). */ /*---------------------------------------------------------------------*/ case R_C6000_ABS32: case R_C6000_ABS16: case R_C6000_ABS8: case R_C6000_ABS_S16: case R_C6000_ABS_L16: case R_C6000_ABS_H16: reloc_value = symval + addend; break; /*---------------------------------------------------------------------*/ /* PC-Relative relocations (calls and branches). */ /*---------------------------------------------------------------------*/ case R_C6000_PCR_S21: case R_C6000_PCR_S12: case R_C6000_PCR_S10: case R_C6000_PCR_S7: { /*------------------------------------------------------------------*/ /* Add SPC to segment address to get the PC. Mask for exec-packet */ /* boundary. */ /*------------------------------------------------------------------*/ int32_t opnd_p = (spc + segment_vaddr) & 0xffffffe0; reloc_value = symval + addend - opnd_p; break; } /*---------------------------------------------------------------------*/ /* "Place"-relative relocations (TDEH). */ /*---------------------------------------------------------------------*/ /* These relocations occur in data and refer to a label that occurs */ /* at some signed 32-bit offset from the place where the relocation */ /* occurs. */ /*---------------------------------------------------------------------*/ case R_C6000_PREL31: { /*------------------------------------------------------------------*/ /* Compute location of relocation entry and subtract it from the */ /* address of the location being referenced (it is computed very */ /* much like a PC-relative relocation, but it occurs in data and */ /* is called a "place"-relative relocation). */ /*------------------------------------------------------------------*/ /* If this is an Elf32_Rel type relocation, then addend is assumed */ /* to have been scaled when it was unpacked (field << 1). */ /*------------------------------------------------------------------*/ /* For Elf32_Rela type relocations the addend is assumed to be a */ /* signed 32-bit integer value. */ /*------------------------------------------------------------------*/ /* Offset is not fetch-packet relative; doesn't need to be masked. */ /*------------------------------------------------------------------*/ int32_t opnd_p = (spc + segment_vaddr); reloc_value = symval + addend - opnd_p; break; } /*---------------------------------------------------------------------*/ /* Static-Base Relative relocations (near-DP). */ /*---------------------------------------------------------------------*/ case R_C6000_SBR_U15_B: case R_C6000_SBR_U15_H: case R_C6000_SBR_U15_W: case R_C6000_SBR_S16: case R_C6000_SBR_L16_B: case R_C6000_SBR_L16_H: case R_C6000_SBR_L16_W: case R_C6000_SBR_H16_B: case R_C6000_SBR_H16_H: case R_C6000_SBR_H16_W: reloc_value = symval + addend - base_pointer; break; /*---------------------------------------------------------------------*/ /* R_C6000_DSBT_INDEX - uses value assigned by the dynamic loader to */ /* be the DSBT index for this module as a scaled offset when */ /* referencing the DSBT. The DSBT base address is in symval and the */ /* static base is in base_pointer. DP-relative offset to slot in */ /* DSBT is the offset of the DSBT relative to the DP plus the */ /* scaled DSBT index into the DSBT. */ /*---------------------------------------------------------------------*/ case R_C6000_DSBT_INDEX: reloc_value = ((symval + addend) - base_pointer) + (dsbt_index << 2); break; /*---------------------------------------------------------------------*/ /* Linux "import-as-own" copy relocation: after DSO initialization, */ /* copy the named object from the DSO into the executable's BSS */ /*---------------------------------------------------------------------*/ /* Linux "import-as-own" copy relocations are not yet supported. */ /*---------------------------------------------------------------------*/ case R_C6000_COPY: /*---------------------------------------------------------------------*/ /* Unrecognized relocation type. */ /*---------------------------------------------------------------------*/ default: DLIF_error(DLET_RELOC, "reloc_do called with invalid relocation type!\n"); break; } /*------------------------------------------------------------------------*/ /* Overflow checking. Is relocation value out of range for the size and */ /* type of the current relocation? */ /*------------------------------------------------------------------------*/ if (rel_overflow(r_type, reloc_value)) DLIF_error(DLET_RELOC, "relocation overflow!\n"); /*------------------------------------------------------------------------*/ /* Move relocation value to appropriate offset for relocation field's */ /* location. */ /*------------------------------------------------------------------------*/ reloc_value = pack_result(reloc_value, r_type); /*------------------------------------------------------------------------*/ /* Mask packed result to the size of the relocation field. */ /*------------------------------------------------------------------------*/ reloc_value = mask_result(reloc_value, r_type); /*------------------------------------------------------------------------*/ /* If necessary, Swap endianness of data at relocation address. */ /*------------------------------------------------------------------------*/ if (wrong_endian) DLIMP_change_endian32((int32_t*)(segment_buffer + spc)); /*------------------------------------------------------------------------*/ /* Write the relocated 4-byte packet back to the segment buffer. */ /*------------------------------------------------------------------------*/ write_reloc_r(segment_buffer, spc, r_type, reloc_value); /*------------------------------------------------------------------------*/ /* Change endianness of segment address back to original. */ /*------------------------------------------------------------------------*/ if (wrong_endian) DLIMP_change_endian32((int32_t*)(segment_buffer + spc)); #if LOADER_DEBUG || LOADER_PROFILE /*------------------------------------------------------------------------*/ /* In profile mode, add elapsed time for this relocation to total time */ /* spent doing relocations. */ /*------------------------------------------------------------------------*/ if (profiling_on) DLREL_total_reloc_time += (clock() - start_time); if (debugging_on) DLIF_trace("reloc_value = 0x%x\n", reloc_value); #endif }