elf32-v850.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,145 行 · 第 1/5 页

C
2,145
字号
	 0xffff,			/* src_mask */	 0xffff,			/* dst_mask */	 false),			/* pcrel_offset */  /* GNU extension to record C++ vtable hierarchy */  HOWTO (R_V850_GNU_VTINHERIT, /* type */         0,                     /* rightshift */         2,                     /* size (0 = byte, 1 = short, 2 = long) */         0,                     /* bitsize */         false,                 /* pc_relative */         0,                     /* bitpos */         complain_overflow_dont, /* complain_on_overflow */         NULL,                  /* special_function */         "R_V850_GNU_VTINHERIT", /* name */         false,                 /* partial_inplace */         0,                     /* src_mask */         0,                     /* dst_mask */         false),                /* pcrel_offset */  /* GNU extension to record C++ vtable member usage */  HOWTO (R_V850_GNU_VTENTRY,     /* type */         0,                     /* rightshift */         2,                     /* size (0 = byte, 1 = short, 2 = long) */         0,                     /* bitsize */         false,                 /* pc_relative */         0,                     /* bitpos */         complain_overflow_dont, /* complain_on_overflow */         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */         "R_V850_GNU_VTENTRY",   /* name */         false,                 /* partial_inplace */         0,                     /* src_mask */         0,                     /* dst_mask */         false),                /* pcrel_offset */};/* Map BFD reloc types to V850 ELF reloc types.  */struct v850_elf_reloc_map{  /* BFD_RELOC_V850_CALLT_16_16_OFFSET is 258, which will not fix in an     unsigned char.  */  bfd_reloc_code_real_type bfd_reloc_val;  unsigned char elf_reloc_val;};static const struct v850_elf_reloc_map v850_elf_reloc_map[] ={  { BFD_RELOC_NONE,		R_V850_NONE },  { BFD_RELOC_V850_9_PCREL,	R_V850_9_PCREL },  { BFD_RELOC_V850_22_PCREL,	R_V850_22_PCREL },  { BFD_RELOC_HI16_S,		R_V850_HI16_S },  { BFD_RELOC_HI16,		R_V850_HI16 },  { BFD_RELOC_LO16,		R_V850_LO16 },  { BFD_RELOC_32,		R_V850_32 },  { BFD_RELOC_16,		R_V850_16 },  { BFD_RELOC_8,		R_V850_8 },  { BFD_RELOC_V850_SDA_16_16_OFFSET, R_V850_SDA_16_16_OFFSET },  { BFD_RELOC_V850_SDA_15_16_OFFSET, R_V850_SDA_15_16_OFFSET },  { BFD_RELOC_V850_ZDA_16_16_OFFSET, R_V850_ZDA_16_16_OFFSET },  { BFD_RELOC_V850_ZDA_15_16_OFFSET, R_V850_ZDA_15_16_OFFSET },  { BFD_RELOC_V850_TDA_6_8_OFFSET,   R_V850_TDA_6_8_OFFSET   },  { BFD_RELOC_V850_TDA_7_8_OFFSET,   R_V850_TDA_7_8_OFFSET   },  { BFD_RELOC_V850_TDA_7_7_OFFSET,   R_V850_TDA_7_7_OFFSET   },  { BFD_RELOC_V850_TDA_16_16_OFFSET, R_V850_TDA_16_16_OFFSET },  { BFD_RELOC_V850_TDA_4_5_OFFSET,         R_V850_TDA_4_5_OFFSET         },  { BFD_RELOC_V850_TDA_4_4_OFFSET,         R_V850_TDA_4_4_OFFSET         },  { BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, R_V850_SDA_16_16_SPLIT_OFFSET },  { BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, R_V850_ZDA_16_16_SPLIT_OFFSET },  { BFD_RELOC_V850_CALLT_6_7_OFFSET,       R_V850_CALLT_6_7_OFFSET       },  { BFD_RELOC_V850_CALLT_16_16_OFFSET,     R_V850_CALLT_16_16_OFFSET     },  { BFD_RELOC_VTABLE_INHERIT,               R_V850_GNU_VTINHERIT },  { BFD_RELOC_VTABLE_ENTRY,                 R_V850_GNU_VTENTRY },};/* Map a bfd relocation into the appropriate howto structure */static reloc_howto_type *v850_elf_reloc_type_lookup (abfd, code)     bfd *                     abfd ATTRIBUTE_UNUSED;     bfd_reloc_code_real_type  code;{  unsigned int i;  for (i = 0;       i < sizeof (v850_elf_reloc_map) / sizeof (struct v850_elf_reloc_map);       i++)    {      if (v850_elf_reloc_map[i].bfd_reloc_val == code)	{	  BFD_ASSERT (v850_elf_howto_table[v850_elf_reloc_map[i].elf_reloc_val].type == v850_elf_reloc_map[i].elf_reloc_val);	  return & v850_elf_howto_table[v850_elf_reloc_map[i].elf_reloc_val];	}    }  return NULL;}/* Set the howto pointer for an V850 ELF reloc.  */static voidv850_elf_info_to_howto_rel (abfd, cache_ptr, dst)     bfd *                 abfd ATTRIBUTE_UNUSED;     arelent *             cache_ptr;     Elf32_Internal_Rel *  dst;{  unsigned int r_type;  r_type = ELF32_R_TYPE (dst->r_info);  BFD_ASSERT (r_type < (unsigned int) R_V850_max);  cache_ptr->howto = &v850_elf_howto_table[r_type];}/* Set the howto pointer for a V850 ELF reloc (type RELA).  */static voidv850_elf_info_to_howto_rela (abfd, cache_ptr, dst)     bfd *                 abfd ATTRIBUTE_UNUSED;     arelent *             cache_ptr;     Elf32_Internal_Rela   *dst;{  unsigned int r_type;  r_type = ELF32_R_TYPE (dst->r_info);  BFD_ASSERT (r_type < (unsigned int) R_V850_max);  cache_ptr->howto = &v850_elf_howto_table[r_type];}/* Look through the relocs for a section during the first phase, and   allocate space in the global offset table or procedure linkage   table.  */static booleanv850_elf_check_relocs (abfd, info, sec, relocs)     bfd *                      abfd;     struct bfd_link_info *     info;     asection *                 sec;     const Elf_Internal_Rela *  relocs;{  boolean ret = true;  bfd *dynobj;  Elf_Internal_Shdr *symtab_hdr;  struct elf_link_hash_entry **sym_hashes;  const Elf_Internal_Rela *rel;  const Elf_Internal_Rela *rel_end;  asection *sreloc;  enum v850_reloc_type r_type;  int other = 0;  const char *common = (const char *)0;  if (info->relocateable)    return true;#ifdef DEBUG  fprintf (stderr, "v850_elf_check_relocs called for section %s in %s\n",	   bfd_get_section_name (abfd, sec),	   bfd_get_filename (abfd));#endif  dynobj = elf_hash_table (info)->dynobj;  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;  sym_hashes = elf_sym_hashes (abfd);  sreloc = NULL;  rel_end = relocs + sec->reloc_count;  for (rel = relocs; rel < rel_end; rel++)    {      unsigned long r_symndx;      struct elf_link_hash_entry *h;      r_symndx = ELF32_R_SYM (rel->r_info);      if (r_symndx < symtab_hdr->sh_info)	h = NULL;      else	h = sym_hashes[r_symndx - symtab_hdr->sh_info];      r_type = (enum v850_reloc_type) ELF32_R_TYPE (rel->r_info);      switch (r_type)	{	default:	case R_V850_NONE:	case R_V850_9_PCREL:	case R_V850_22_PCREL:	case R_V850_HI16_S:	case R_V850_HI16:	case R_V850_LO16:	case R_V850_32:	case R_V850_16:	case R_V850_8:	case R_V850_CALLT_6_7_OFFSET:	case R_V850_CALLT_16_16_OFFSET:	  break;        /* This relocation describes the C++ object vtable hierarchy.           Reconstruct it for later use during GC.  */        case R_V850_GNU_VTINHERIT:          if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))            return false;          break;        /* This relocation describes which C++ vtable entries are actually           used.  Record for later use during GC.  */        case R_V850_GNU_VTENTRY:          if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))            return false;          break;	case R_V850_SDA_16_16_SPLIT_OFFSET:	case R_V850_SDA_16_16_OFFSET:	case R_V850_SDA_15_16_OFFSET:	  other = V850_OTHER_SDA;	  common = ".scommon";	  goto small_data_common;	case R_V850_ZDA_16_16_SPLIT_OFFSET:	case R_V850_ZDA_16_16_OFFSET:	case R_V850_ZDA_15_16_OFFSET:	  other = V850_OTHER_ZDA;	  common = ".zcommon";	  goto small_data_common;	case R_V850_TDA_4_5_OFFSET:	case R_V850_TDA_4_4_OFFSET:	case R_V850_TDA_6_8_OFFSET:	case R_V850_TDA_7_8_OFFSET:	case R_V850_TDA_7_7_OFFSET:	case R_V850_TDA_16_16_OFFSET:	  other = V850_OTHER_TDA;	  common = ".tcommon";	  /* fall through */#define V850_OTHER_MASK (V850_OTHER_TDA | V850_OTHER_SDA | V850_OTHER_ZDA)	small_data_common:	  if (h)	    {	      h->other |= other;	/* flag which type of relocation was used */	      if ((h->other & V850_OTHER_MASK) != (other & V850_OTHER_MASK)		  && (h->other & V850_OTHER_ERROR) == 0)		{		  const char * msg;		  static char  buff[200]; /* XXX */		  switch (h->other & V850_OTHER_MASK)		    {		    default:		      msg = _("Variable `%s' cannot occupy in multiple small data regions");		      break;		    case V850_OTHER_SDA | V850_OTHER_ZDA | V850_OTHER_TDA:		      msg = _("Variable `%s' can only be in one of the small, zero, and tiny data regions");		      break;		    case V850_OTHER_SDA | V850_OTHER_ZDA:		      msg = _("Variable `%s' cannot be in both small and zero data regions simultaneously");		      break;		    case V850_OTHER_SDA | V850_OTHER_TDA:		      msg = _("Variable `%s' cannot be in both small and tiny data regions simultaneously");		      break;		    case V850_OTHER_ZDA | V850_OTHER_TDA:		      msg = _("Variable `%s' cannot be in both zero and tiny data regions simultaneously");		      break;		    }		  sprintf (buff, msg, h->root.root.string);		  info->callbacks->warning (info, buff, h->root.root.string,					    abfd, h->root.u.def.section, 0);		  bfd_set_error (bfd_error_bad_value);		  h->other |= V850_OTHER_ERROR;		  ret = false;		}	    }	  if (h && h->root.type == bfd_link_hash_common	      && h->root.u.c.p	      && !strcmp (bfd_get_section_name (abfd, h->root.u.c.p->section), "COMMON"))	    {	      asection *section = h->root.u.c.p->section = bfd_make_section_old_way (abfd, common);	      section->flags |= SEC_IS_COMMON;	    }#ifdef DEBUG	  fprintf (stderr, "v850_elf_check_relocs, found %s relocation for %s%s\n",		   v850_elf_howto_table[ (int)r_type ].name,		   (h && h->root.root.string) ? h->root.root.string : "<unknown>",		   (h->root.type == bfd_link_hash_common) ? ", symbol is common" : "");#endif	  break;	}    }  return ret;}/* * In the old version, when an entry was checked out from the table, * it was deleted.  This produced an error if the entry was needed * more than once, as the second attempted retry failed. * * In the current version, the entry is not deleted, instead we set * the field 'found' to true.  If a second lookup matches the same * entry, then we know that the hi16s reloc has already been updated * and does not need to be updated a second time. * * TODO - TOFIX: If it is possible that we need to restore 2 different * addresses from the same table entry, where the first generates an * overflow, whilst the second do not, then this code will fail. */typedef struct hi16s_location{  bfd_vma       addend;  bfd_byte *    address;  unsigned long counter;  boolean       found;  struct hi16s_location * next;}hi16s_location;static hi16s_location *  previous_hi16s;static hi16s_location *  free_hi16s;static unsigned long     hi16s_counter;static voidremember_hi16s_reloc (abfd, addend, address)     bfd *      abfd;     bfd_vma    addend;     bfd_byte * address;{  hi16s_location * entry = NULL;  /* Find a free structure.  */  if (free_hi16s == NULL)    free_hi16s = (hi16s_location *) bfd_zalloc (abfd, sizeof (* free_hi16s));  entry      = free_hi16s;  free_hi16s = free_hi16s->next;  entry->addend  = addend;  entry->address = address;  entry->counter = hi16s_counter ++;  entry->found   = false;  entry->next    = previous_hi16s;  previous_hi16s = entry;  /* Cope with wrap around of our counter.  */  if (hi16s_counter == 0)    {      /* XXX - Assume that all counter entries differ only in their low 16 bits.  */      for (entry = previous_hi16s; entry != NULL; entry = entry->next)	entry->counter &= 0xffff;      hi16s_counter = 0x10000;    }  return;}static bfd_byte *find_remembered_hi16s_reloc (addend, already_found)     bfd_vma   addend;     boolean * already_found;{  hi16s_location * match = NULL;  hi16s_location * entry;  hi16s_location * previous = NULL;  hi16s_location * prev;  bfd_byte *       addr;  /* Search the table.  Record the most recent entry that matches.  */  for (entry = previous_hi16s; entry; entry = entry->next)    {      if (entry->addend == addend	  && (match == NULL || match->counter < entry->counter))	{	  previous = prev;	  match    = entry;	}      prev = entry;    }  if (match == NULL)    return NULL;  /* Extract the address.  */  addr = match->address;  /* Remeber if this entry has already been used before.  */  if (already_found)    * already_found = match->found;  /* Note that this entry has now been used.  */  match->found = true;  return addr;}/* FIXME:  The code here probably ought to be removed and the code in reloc.c   allowed to do its  stuff instead.  At least for most of the relocs, anwyay.  */static bfd_reloc_status_typev850_elf_perform_relocation (abfd, r_type, addend, address)     bfd *      abfd;     int        r_type;     bfd_vma    addend;     bfd_byte * address;{  unsigned long insn;  bfd_signed_vma saddend = (bfd_signed_vma) addend;  switch (r_type)    {    default:      /* fprintf (stderr, "reloc type %d not SUPPORTED\n", r_type ); */      return bfd_reloc_notsupported;    case R_V850_32:      bfd_put_32 (abfd, addend, address);      return bfd_reloc_ok;    case R_V850_22_PCREL:      if (saddend > 0x1fffff || saddend < -0x200000)	return bfd_reloc_overflow;      if ((addend % 2) != 0)	return bfd_reloc_dangerous;      insn  = bfd_get_32 (abfd, address);      insn &= ~0xfffe003f;      insn |= (((addend & 0xfffe) << 16) | ((addend & 0x3f0000) >> 16));      bfd_put_32 (abfd, insn, address);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?