static BOOL rel_overflow(C60_RELOC_TYPE r_type, int32_t reloc_value) { /*------------------------------------------------------------------------*/ /* Select appropriate range check based on relocation type. */ /*------------------------------------------------------------------------*/ switch(r_type) { case R_C6000_ABS16: return ((reloc_value > 65535) || (reloc_value < -32768)); case R_C6000_ABS8: return ((reloc_value > 255) || (reloc_value < -128)); case R_C6000_PCR_S21: return ((reloc_value >= 0x400000) || (reloc_value < -0x400000)); case R_C6000_PCR_S12: return ((reloc_value >= 0x2000) || (reloc_value < -0x2000)); case R_C6000_PCR_S10: return ((reloc_value >= 0x800) || (reloc_value < -0x800)); case R_C6000_PCR_S7: return ((reloc_value >= 0x100) || (reloc_value < -0x100)); case R_C6000_SBR_S16: case R_C6000_ABS_S16: return ((reloc_value >= 0x8000) || (reloc_value < -0x8000)); case R_C6000_SBR_U15_B: return (((uint32_t)reloc_value) >= 0x8000); case R_C6000_SBR_U15_H: return (((uint32_t)reloc_value) >= 0xFFFF); case R_C6000_DSBT_INDEX: case R_C6000_SBR_U15_W: return (((uint32_t)reloc_value) >= 0x1FFFD); /*---------------------------------------------------------------------*/ /* Some relocation types suppress overflow checking at link-time. */ /*---------------------------------------------------------------------*/ case R_C6000_ABS_L16: case R_C6000_ABS_H16: 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: return 0; /*---------------------------------------------------------------------*/ /* 32-bit relocation field values are not checked for overflow. */ /*---------------------------------------------------------------------*/ case R_C6000_ABS32: case R_C6000_PREL31: return 0; /*---------------------------------------------------------------------*/ /* If relocation type did not appear in the above switch, then we */ /* didn't expect to see it. */ /*---------------------------------------------------------------------*/ default: DLIF_error(DLET_RELOC, "rel_overflow called with invalid relocation type!\n"); } return 1; }
static void process_pltgot_relocs(DLOAD_HANDLE handle, void* plt_reloc_table, int reltype, uint32_t pltnum, DLIMP_Dynamic_Module* dyn_module) { Elf32_Addr r_offset = (reltype == DT_REL) ? ((struct Elf32_Rel *)plt_reloc_table)->r_offset : ((struct Elf32_Rela *)plt_reloc_table)->r_offset; DLIMP_Loaded_Segment* seg = (DLIMP_Loaded_Segment*)(dyn_module->loaded_module->loaded_segments.buf); uint32_t num_segs = dyn_module->loaded_module->loaded_segments.size; int32_t plt_relidx = 0; uint32_t seg_idx = 0; uint32_t ti_static_base = 0; /*------------------------------------------------------------------------*/ /* Get the value of the static base (__TI_STATIC_BASE) which will be */ /* passed into the relocation table processing functions. */ /*------------------------------------------------------------------------*/ if (!DLSYM_lookup_local_symtab("__TI_STATIC_BASE", dyn_module->symtab, dyn_module->symnum, &ti_static_base)) DLIF_error(DLET_RELOC, "Could not resolve value of __TI_STATIC_BASE\n"); /*------------------------------------------------------------------------*/ /* For each segment s, check if the relocation falls within s. If so, */ /* then all other relocations are guaranteed to fall with s. Process */ /* all relocations and then return. */ /*------------------------------------------------------------------------*/ for (seg_idx = 0; seg_idx < num_segs; seg_idx++) { Elf32_Addr seg_start_addr = seg[seg_idx].input_vaddr; Elf32_Addr seg_end_addr = seg_start_addr + seg[seg_idx].phdr.p_memsz; /*---------------------------------------------------------------------*/ /* Relocations should not occur in uninitialized segments. */ /*---------------------------------------------------------------------*/ if(!seg[seg_idx].phdr.p_filesz) continue; if (r_offset >= seg_start_addr && r_offset < seg_end_addr) { if (reltype == DT_REL) process_rel_table(handle, (seg + seg_idx), (struct Elf32_Rel *)plt_reloc_table, pltnum, &plt_relidx, ti_static_base, dyn_module); else process_rela_table(handle, (seg + seg_idx), (struct Elf32_Rela *)plt_reloc_table, pltnum, &plt_relidx, ti_static_base, dyn_module); break; } } }
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); } }
static int32_t mask_result(int32_t unmasked_result, int r_type) { switch(r_type) { case R_C6000_ABS8: return unmasked_result & 0xFF; case R_C6000_ABS32: return unmasked_result; case R_C6000_ABS16: case R_C6000_ABS_S16: case R_C6000_ABS_L16: case R_C6000_ABS_H16: 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: return unmasked_result & 0xFFFF; case R_C6000_PCR_S21: return unmasked_result & 0x1FFFFF; case R_C6000_PCR_S12: return unmasked_result & 0xFFF; case R_C6000_PCR_S10: return unmasked_result & 0x3FF; case R_C6000_PCR_S7: return unmasked_result & 0x7F; case R_C6000_SBR_U15_B: case R_C6000_SBR_U15_H: case R_C6000_SBR_U15_W: case R_C6000_DSBT_INDEX: return unmasked_result & 0x7FFF; case R_C6000_PREL31: return unmasked_result & 0x7FFFFFFF; /*---------------------------------------------------------------------*/ /* Linux "import-as-own" copy relocations are not yet supported. */ /*---------------------------------------------------------------------*/ case R_C6000_COPY: default: DLIF_error(DLET_RELOC, "mask_result called with invalid relocation type!\n"); return 0; } }
static void rel_unpack_addend(C60_RELOC_TYPE r_type, uint8_t *address, uint32_t *addend) { /*------------------------------------------------------------------------*/ /* C6000 does not support Elf32_Rel type relocations in the dynamic */ /* loader core. We will emit an internal error and abort until this */ /* support is added. I abort here because this is necessarily a target- */ /* specific part of the relocation infrastructure. */ /*------------------------------------------------------------------------*/ *addend = 0; DLIF_error(DLET_RELOC, "Internal Error: unpacking addend values from the relocation " "field is not supported in the C6000 dynamic loader at this " "time; aborting\n"); DLIF_exit(1); }
static void process_got_relocs(DLOAD_HANDLE handle, struct Elf32_Rel* rel_table, uint32_t relnum, struct Elf32_Rela* rela_table, uint32_t relanum, DLIMP_Dynamic_Module* dyn_module) { DLIMP_Loaded_Segment *seg = (DLIMP_Loaded_Segment*)(dyn_module->loaded_module->loaded_segments.buf); uint32_t num_segs = dyn_module->loaded_module->loaded_segments.size; int32_t rel_relidx = 0; int32_t rela_relidx = 0; uint32_t seg_idx = 0; uint32_t ti_static_base = 0; /*------------------------------------------------------------------------*/ /* Get the value of the static base (__TI_STATIC_BASE) which will be */ /* passed into the relocation table processing functions. */ /*------------------------------------------------------------------------*/ if (!DLSYM_lookup_local_symtab("__TI_STATIC_BASE", dyn_module->symtab, dyn_module->symnum, &ti_static_base)) DLIF_error(DLET_RELOC, "Could not resolve value of __TI_STATIC_BASE\n"); /*------------------------------------------------------------------------*/ /* Process relocations segment by segment. */ /*------------------------------------------------------------------------*/ for (seg_idx = 0; seg_idx < num_segs; seg_idx++) { /*---------------------------------------------------------------------*/ /* Relocations should not occur in uninitialized segments. */ /*---------------------------------------------------------------------*/ if (!seg[seg_idx].phdr.p_filesz) continue; if (rela_table) process_rela_table(handle, (seg + seg_idx), rela_table, relanum, &rela_relidx, ti_static_base, dyn_module); if (rel_table) process_rel_table(handle, (seg + seg_idx), rel_table, relnum, &rel_relidx, ti_static_base, dyn_module); } }
BOOL DLIF_update_all_dsbts() { /*------------------------------------------------------------------------*/ /* Spin through the client's master copy of the DSBT. For each entry in */ /* the table: */ /* */ /* 1. Check the DSBT size for the module that is associated with the */ /* current slot in the DSBT to see if its DSBT size is large enough */ /* to hold a copy of the master DSBT. */ /* */ /* 2. Query the core loader for the static base value associated with */ /* the module that has been assigned to the current index in the */ /* DSBT. This static base value is recorded in the client's DSBT */ /* model. */ /* */ /* 3. Query the core loader for the DSBT base value associated with */ /* the module that has been assigned to the current index in the */ /* master DSBT. We should only look this value up once while the */ /* file is still open and its dynamic module object is still */ /* available. */ /* */ /*------------------------------------------------------------------------*/ int32_t i; int32_t master_dsbt_size = AL_size(&DSBT_master); DSBT_Entry *client_dsbt = (DSBT_Entry *)(DSBT_master.buf); DSBT_Index_Request *curr_req = NULL; #if LOADER_DEBUG if (debugging_on) { printf("Starting DLIF_update_all_dsbts() ... \n"); printf("Size of master DSBT is %d\n", master_dsbt_size); dump_master_dsbt(); } #endif /*------------------------------------------------------------------------*/ /* Spin through the master DSBT model and fill in details about the DSBT */ /* base and the static base associated with each module that has been */ /* assigned a slot in the master DSBT. */ /*------------------------------------------------------------------------*/ for (i = 0; i < master_dsbt_size; i++) { curr_req = client_dsbt[i].index_request; /*---------------------------------------------------------------------*/ /* We only need to worry about filling in details for slots that have */ /* actually been assigned to an object module (if this slot doesn't */ /* have a DSBT index request record associated with it, then it is */ /* "available"). */ /*---------------------------------------------------------------------*/ if (curr_req != NULL) { /*------------------------------------------------------------------*/ /* If the DSBT size has not been filled in for the module that is */ /* assigned to this slot, look it up in the local symbol table of */ /* the module. We have to do this while the dynamic module object */ /* for the module is still open (it has a copy of the local symbol */ /* table). */ /*------------------------------------------------------------------*/ uint32_t curr_dsbt_size = curr_req->dsbt_size; if (curr_dsbt_size < master_dsbt_size) { DLIF_error(DLET_MISC, "DSBT allocated for %s is not large enough to hold " "entire DSBT", curr_req->name); return FALSE; } } } /*------------------------------------------------------------------------*/ /* Now write a copy of the DSBT for each module that uses the DSBT model. */ /* We need to find the DSBT base for each module represented in the */ /* master DSBT, then we can write the content of the master DSBT to each */ /* DSBT base location. */ /*------------------------------------------------------------------------*/ for (i = 0; i < master_dsbt_size; i++) { curr_req = client_dsbt[i].index_request; /*---------------------------------------------------------------------*/ /* Write content of master DSBT to location of module's DSBT. */ /*---------------------------------------------------------------------*/ if (curr_req != NULL) { int j; #if LOADER_DEBUG if (debugging_on) printf("Writing master DSBT to 0x%08lx for module: %s\n", curr_req->dsbt_base, curr_req->name); #endif for (j = 0; j < master_dsbt_size; j++) { DSBT_Index_Request *j_req = client_dsbt[j].index_request; if (j_req != NULL) *((TARGET_ADDRESS *)(curr_req->dsbt_base) + j) = (j_req != NULL) ? j_req->static_base : 0; } } } #if LOADER_DEBUG if (debugging_on) dump_master_dsbt(); #endif return TRUE; }
BOOL DLIF_register_dsbt_index_request(DLOAD_HANDLE handle, const char *requestor_name, int32_t requestor_file_handle, int32_t requested_dsbt_index) { DSBT_Index_Request *new_request = NULL; /*------------------------------------------------------------------------*/ /* If requesting a specific DSBT index, check existing list of DSBT index */ /* requests to see if we've already seen a request for the specified */ /* DSBT index or if a request has already been received on behalf of the */ /* specified file. Both cases constitute an error and will abort the */ /* load. */ /*------------------------------------------------------------------------*/ if (requested_dsbt_index != DSBT_INDEX_INVALID) { dsbt_index_request_ptr_Queue_Node *ptr; /*---------------------------------------------------------------------*/ /* If the client's master DSBT model already has content, then check */ /* to see if the requested DSBT index is available in the master DSBT. */ /*---------------------------------------------------------------------*/ if (AL_size(&DSBT_master) > requested_dsbt_index) { DSBT_Entry *client_dsbt = (DSBT_Entry *)(DSBT_master.buf); if (client_dsbt[requested_dsbt_index].index_request != NULL) { DLIF_error(DLET_MISC, "%s is requesting a DSBT index, %d, that is already " "being used by an active module, %s", requestor_name, requested_dsbt_index, client_dsbt[requested_dsbt_index].index_request->name); return FALSE; } } for (ptr = DSBT_index_request_queue.front_ptr; ptr != NULL; ptr = ptr->next_ptr) { DSBT_Index_Request *existing_request = ptr->value; /*------------------------------------------------------------------*/ /* Have we seen a request for this file already? That would be a */ /* problem (likely internal). */ /*------------------------------------------------------------------*/ if (requestor_file_handle == existing_request->file_handle) { DLIF_error(DLET_MISC, "A DSBT index has already been requested on behalf " "of %s; cannot make a second DSBT index request for " "the same module", existing_request->name); return FALSE; } /*------------------------------------------------------------------*/ /* Have we seen a specific request for this DSBT index already? */ /* Report a conflict among specific requests in the same load. */ /*------------------------------------------------------------------*/ if (requested_dsbt_index == existing_request->requested_index) { DLIF_error(DLET_MISC, "Requested DSBT index, %d, requested by %s has " "already been requested by %s; load aborted", requested_dsbt_index, requestor_name, existing_request->name); return FALSE; } } } /*------------------------------------------------------------------------*/ /* If specified module is requesting a specific DSBT index that hasn't */ /* been encountered yet, or if it is making a general DSBT index request */ /* (to be assigned by the client when the current top-level load is */ /* sucessfully completed), make a DSBT index request entry for the */ /* current module and add it to the DSBT_Index_Request_List. */ /*------------------------------------------------------------------------*/ new_request = (DSBT_Index_Request *)DLIF_malloc(sizeof(DSBT_Index_Request)); new_request->name = (char *)DLIF_malloc(strlen(requestor_name) + 1); strcpy(new_request->name, requestor_name); new_request->file_handle = requestor_file_handle; new_request->dsbt_size = DLOAD_get_dsbt_size(handle, requestor_file_handle); if (!DLOAD_get_dsbt_base(handle, requestor_file_handle, &new_request->dsbt_base)) { DLIF_error(DLET_MISC, "Could not resolve DSBT base value for %s", requestor_name); DLIF_free(new_request->name); new_request->name = NULL; DLIF_free(new_request); new_request = NULL; return FALSE; } if (!DLOAD_get_static_base(handle, requestor_file_handle, &new_request->static_base)) { DLIF_error(DLET_MISC, "Could not resolve static base value for %s", requestor_name); DLIF_free(new_request->name); new_request->name = NULL; DLIF_free(new_request); new_request = NULL; return FALSE; } new_request->requested_index = requested_dsbt_index; new_request->assigned_index = DSBT_INDEX_INVALID; dsbt_index_request_ptr_enqueue(&DSBT_index_request_queue, new_request); return TRUE; }
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; }
void DLREL_c60_relocate(DLOAD_HANDLE handle, LOADER_FILE_DESC *fd, DLIMP_Dynamic_Module *dyn_module) { struct Elf32_Dyn *dyn_nugget = dyn_module->dyntab; struct Elf32_Rela *rela_table = NULL; struct Elf32_Rel *rel_table = NULL; struct Elf32_Rela *rela_plt_table = NULL; struct Elf32_Rel *rel_plt_table = NULL; /*------------------------------------------------------------------------*/ /* Read the size of the relocation table (DT_RELASZ) and the size per */ /* relocation (DT_RELAENT) from the dynamic segment. */ /*------------------------------------------------------------------------*/ uint32_t relasz = DLIMP_get_first_dyntag(DT_RELASZ, dyn_nugget); uint32_t relaent = DLIMP_get_first_dyntag(DT_RELAENT, dyn_nugget); uint32_t relanum = 0; /*------------------------------------------------------------------------*/ /* Read the size of the relocation table (DT_RELSZ) and the size per */ /* relocation (DT_RELENT) from the dynamic segment. */ /*------------------------------------------------------------------------*/ uint32_t relsz = DLIMP_get_first_dyntag(DT_RELSZ, dyn_nugget); uint32_t relent = DLIMP_get_first_dyntag(DT_RELENT, dyn_nugget); uint32_t relnum = 0; /*------------------------------------------------------------------------*/ /* Read the size of the relocation table (DT_PLTRELSZ) and the type of */ /* of the PLTGOT relocation table (DT_PLTREL): one of DT_REL or DT_RELA */ /*------------------------------------------------------------------------*/ uint32_t pltrelsz = DLIMP_get_first_dyntag(DT_PLTRELSZ, dyn_nugget); int pltreltyp = DLIMP_get_first_dyntag(DT_PLTREL, dyn_nugget); uint32_t pltnum = 0; /*------------------------------------------------------------------------*/ /* Find/record DSBT index associated with this module. */ /*------------------------------------------------------------------------*/ if (is_dsbt_module(dyn_module) && (dyn_module->dsbt_index == DSBT_INDEX_INVALID)) dyn_module->dsbt_index = DLIF_get_dsbt_index(dyn_module->loaded_module->file_handle); /*------------------------------------------------------------------------*/ /* Read the PLTGOT relocation table from the file */ /* The PLTGOT table is a subsection at the end of either the DT_REL or */ /* DT_RELA table. The size of the table it belongs to DT_REL(A)SZ */ /* includes the size of the PLTGOT table. So it must be adjusted so that */ /* the GOT relocation tables only contain actual GOT relocations. */ /*------------------------------------------------------------------------*/ if (pltrelsz != INT_MAX && pltrelsz != 0) { if (pltreltyp == DT_REL) { pltnum = pltrelsz/relent; relsz -= pltrelsz; read_rel_table((&rel_plt_table), DLIMP_get_first_dyntag(DT_JMPREL, dyn_nugget), pltnum, relent, fd, dyn_module->wrong_endian); } else if (pltreltyp == DT_RELA) { pltnum = pltrelsz/relaent; relasz -= pltrelsz; read_rela_table((&rela_plt_table), DLIMP_get_first_dyntag(DT_JMPREL, dyn_nugget), pltnum, relaent, fd, dyn_module->wrong_endian); } else { DLIF_error(DLET_RELOC, "DT_PLTREL is invalid: must be either %d or %d\n", DT_REL, DT_RELA); } } /*------------------------------------------------------------------------*/ /* Read the DT_RELA GOT relocation table from the file */ /*------------------------------------------------------------------------*/ if (relasz != INT_MAX && relasz != 0) { relanum = relasz/relaent; read_rela_table(&rela_table, DLIMP_get_first_dyntag(DT_RELA, dyn_nugget), relanum, relaent, fd, dyn_module->wrong_endian); } /*------------------------------------------------------------------------*/ /* Read the DT_REL GOT relocation table from the file */ /*------------------------------------------------------------------------*/ if (relsz != INT_MAX && relsz != 0) { relnum = relsz/relent; read_rel_table(&rel_table, DLIMP_get_first_dyntag(DT_REL, dyn_nugget), relnum, relent, fd, dyn_module->wrong_endian); } /*------------------------------------------------------------------------*/ /* Process the PLTGOT relocations */ /*------------------------------------------------------------------------*/ if (rela_plt_table) process_pltgot_relocs(handle, rela_plt_table, pltreltyp, pltnum, dyn_module); if (rel_plt_table) process_pltgot_relocs(handle, rel_plt_table, pltreltyp, pltnum, dyn_module); /*------------------------------------------------------------------------*/ /* Process the GOT relocations */ /*------------------------------------------------------------------------*/ if (rel_table || rela_table) process_got_relocs(handle, rel_table, relnum, rela_table, relanum, dyn_module); /*-------------------------------------------------------------------------*/ /* Free memory used for ELF relocation table copies. */ /*-------------------------------------------------------------------------*/ if (rela_table) DLIF_free(rela_table); if (rel_table) DLIF_free(rel_table); if (rela_plt_table) DLIF_free(rela_plt_table); if (rel_plt_table) DLIF_free(rel_plt_table); }
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 }