Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
      }
   }
}
Esempio n. 3
0
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);
   }
}
Esempio n. 4
0
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;
   }
}
Esempio n. 5
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);
}
Esempio n. 6
0
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);
   }
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
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
}
Esempio n. 12
0
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
}