elf32-hppa.c

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

C
2,142
字号
     subclass.  */  if (ret == NULL)    {      ret = ((struct elf32_hppa_stub_hash_entry *)	     bfd_hash_allocate (table,				sizeof (struct elf32_hppa_stub_hash_entry)));      if (ret == NULL)	return NULL;    }  /* Call the allocation method of the superclass.  */  ret = ((struct elf32_hppa_stub_hash_entry *)	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));  if (ret)    {      /* Initialize the local fields.  */      ret->stub_sec = NULL;#if ! LONG_BRANCH_PIC_IN_SHLIB      ret->reloc_sec = NULL;#endif      ret->stub_offset = 0;      ret->target_value = 0;      ret->target_section = NULL;      ret->stub_type = hppa_stub_long_branch;      ret->h = NULL;      ret->id_sec = NULL;    }  return (struct bfd_hash_entry *) ret;}/* Initialize an entry in the link hash table.  */static struct bfd_hash_entry *hppa_link_hash_newfunc (entry, table, string)     struct bfd_hash_entry *entry;     struct bfd_hash_table *table;     const char *string;{  struct elf32_hppa_link_hash_entry *ret;  ret = (struct elf32_hppa_link_hash_entry *) entry;  /* Allocate the structure if it has not already been allocated by a     subclass.  */  if (ret == NULL)    {      ret = ((struct elf32_hppa_link_hash_entry *)	     bfd_hash_allocate (table,				sizeof (struct elf32_hppa_link_hash_entry)));      if (ret == NULL)	return NULL;    }  /* Call the allocation method of the superclass.  */  ret = ((struct elf32_hppa_link_hash_entry *)	 _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,				     table, string));  if (ret)    {      /* Initialize the local fields.  */#if ! LONG_BRANCH_PIC_IN_SHLIB      ret->stub_reloc_sec = NULL;#endif      ret->stub_cache = NULL;#if ! LONG_BRANCH_PIC_IN_SHLIB || RELATIVE_DYNAMIC_RELOCS      ret->reloc_entries = NULL;#endif      ret->maybe_pic_call = 0;      ret->pic_call = 0;      ret->plabel = 0;      ret->plt_abs = 0;    }  return (struct bfd_hash_entry *) ret;}/* Create the derived linker hash table.  The PA ELF port uses the derived   hash table to keep information specific to the PA ELF linker (without   using static variables).  */static struct bfd_link_hash_table *elf32_hppa_link_hash_table_create (abfd)     bfd *abfd;{  struct elf32_hppa_link_hash_table *ret;  ret = ((struct elf32_hppa_link_hash_table *) bfd_alloc (abfd, sizeof (*ret)));  if (ret == NULL)    return NULL;  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, hppa_link_hash_newfunc))    {      bfd_release (abfd, ret);      return NULL;    }  /* Init the stub hash table too.  */  if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc))    return NULL;  ret->stub_bfd = NULL;  ret->add_stub_section = NULL;  ret->layout_sections_again = NULL;  ret->stub_group = NULL;  ret->sgot = NULL;  ret->srelgot = NULL;  ret->splt = NULL;  ret->srelplt = NULL;  ret->sdynbss = NULL;  ret->srelbss = NULL;  ret->text_segment_base = (bfd_vma) -1;  ret->data_segment_base = (bfd_vma) -1;  ret->multi_subspace = 0;  ret->has_12bit_branch = 0;  ret->has_17bit_branch = 0;  ret->need_plt_stub = 0;  return &ret->root.root;}/* Build a name for an entry in the stub hash table.  */static char *hppa_stub_name (input_section, sym_sec, hash, rel)     const asection *input_section;     const asection *sym_sec;     const struct elf32_hppa_link_hash_entry *hash;     const Elf_Internal_Rela *rel;{  char *stub_name;  size_t len;  if (hash)    {      len = 8 + 1 + strlen (hash->elf.root.root.string) + 1 + 8 + 1;      stub_name = bfd_malloc (len);      if (stub_name != NULL)	{	  sprintf (stub_name, "%08x_%s+%x",		   input_section->id & 0xffffffff,		   hash->elf.root.root.string,		   (int) rel->r_addend & 0xffffffff);	}    }  else    {      len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1;      stub_name = bfd_malloc (len);      if (stub_name != NULL)	{	  sprintf (stub_name, "%08x_%x:%x+%x",		   input_section->id & 0xffffffff,		   sym_sec->id & 0xffffffff,		   (int) ELF32_R_SYM (rel->r_info) & 0xffffffff,		   (int) rel->r_addend & 0xffffffff);	}    }  return stub_name;}/* Look up an entry in the stub hash.  Stub entries are cached because   creating the stub name takes a bit of time.  */static struct elf32_hppa_stub_hash_entry *hppa_get_stub_entry (input_section, sym_sec, hash, rel, hplink)     const asection *input_section;     const asection *sym_sec;     struct elf32_hppa_link_hash_entry *hash;     const Elf_Internal_Rela *rel;     struct elf32_hppa_link_hash_table *hplink;{  struct elf32_hppa_stub_hash_entry *stub_entry;  const asection *id_sec;  /* If this input section is part of a group of sections sharing one     stub section, then use the id of the first section in the group.     Stub names need to include a section id, as there may well be     more than one stub used to reach say, printf, and we need to     distinguish between them.  */  id_sec = hplink->stub_group[input_section->id].link_sec;  if (hash != NULL && hash->stub_cache != NULL      && hash->stub_cache->h == hash      && hash->stub_cache->id_sec == id_sec)    {      stub_entry = hash->stub_cache;    }  else    {      char *stub_name;      stub_name = hppa_stub_name (id_sec, sym_sec, hash, rel);      if (stub_name == NULL)	return NULL;      stub_entry = hppa_stub_hash_lookup (&hplink->stub_hash_table,					  stub_name, false, false);      if (stub_entry == NULL)	{	  if (hash == NULL || hash->elf.root.type != bfd_link_hash_undefweak)	    (*_bfd_error_handler) (_("%s(%s+0x%lx): cannot find stub entry %s"),				   bfd_get_filename (input_section->owner),				   input_section->name,				   (long) rel->r_offset,				   stub_name);	}      else	{	  if (hash != NULL)	    hash->stub_cache = stub_entry;	}      free (stub_name);    }  return stub_entry;}/* Add a new stub entry to the stub hash.  Not all fields of the new   stub entry are initialised.  */static struct elf32_hppa_stub_hash_entry *hppa_add_stub (stub_name, section, hplink)     const char *stub_name;     asection *section;     struct elf32_hppa_link_hash_table *hplink;{  asection *link_sec;  asection *stub_sec;  struct elf32_hppa_stub_hash_entry *stub_entry;  link_sec = hplink->stub_group[section->id].link_sec;  stub_sec = hplink->stub_group[section->id].stub_sec;  if (stub_sec == NULL)    {      stub_sec = hplink->stub_group[link_sec->id].stub_sec;      if (stub_sec == NULL)	{	  size_t len;	  char *s_name;	  len = strlen (link_sec->name) + sizeof (STUB_SUFFIX);	  s_name = bfd_alloc (hplink->stub_bfd, len);	  if (s_name == NULL)	    return NULL;	  strcpy (s_name, link_sec->name);	  strcpy (s_name + len - sizeof (STUB_SUFFIX), STUB_SUFFIX);	  stub_sec = (*hplink->add_stub_section) (s_name, link_sec);	  if (stub_sec == NULL)	    return NULL;	  hplink->stub_group[link_sec->id].stub_sec = stub_sec;	}      hplink->stub_group[section->id].stub_sec = stub_sec;    }  /* Enter this entry into the linker stub hash table.  */  stub_entry = hppa_stub_hash_lookup (&hplink->stub_hash_table, stub_name,				      true, false);  if (stub_entry == NULL)    {      (*_bfd_error_handler) (_("%s: cannot create stub entry %s"),			     bfd_get_filename (section->owner),			     stub_name);      return NULL;    }  stub_entry->stub_sec = stub_sec;#if ! LONG_BRANCH_PIC_IN_SHLIB  stub_entry->reloc_sec = hplink->stub_group[section->id].reloc_sec;#endif  stub_entry->stub_offset = 0;  stub_entry->id_sec = link_sec;  return stub_entry;}/* Determine the type of stub needed, if any, for a call.  */static enum elf32_hppa_stub_typehppa_type_of_stub (input_sec, rel, hash, destination)     asection *input_sec;     const Elf_Internal_Rela *rel;     struct elf32_hppa_link_hash_entry *hash;     bfd_vma destination;{  bfd_vma location;  bfd_vma branch_offset;  bfd_vma max_branch_offset;  unsigned int r_type;  if (hash != NULL      && (((hash->elf.root.type == bfd_link_hash_defined	    || hash->elf.root.type == bfd_link_hash_defweak)	   && hash->elf.root.u.def.section->output_section == NULL)	  || (hash->elf.root.type == bfd_link_hash_defweak	      && hash->elf.dynindx != -1	      && hash->elf.plt.offset != (bfd_vma) -1)	  || hash->elf.root.type == bfd_link_hash_undefweak	  || hash->elf.root.type == bfd_link_hash_undefined	  || (hash->maybe_pic_call && !(input_sec->flags & SEC_HAS_GOT_REF))))    {      /* If output_section is NULL, then it's a symbol defined in a	 shared library.  We will need an import stub.  Decide between	 hppa_stub_import and hppa_stub_import_shared later.  For	 shared links we need stubs for undefined or weak syms too;	 They will presumably be resolved by the dynamic linker.  */      return hppa_stub_import;    }  /* Determine where the call point is.  */  location = (input_sec->output_offset	      + input_sec->output_section->vma	      + rel->r_offset);  branch_offset = destination - location - 8;  r_type = ELF32_R_TYPE (rel->r_info);  /* Determine if a long branch stub is needed.  parisc branch offsets     are relative to the second instruction past the branch, ie. +8     bytes on from the branch instruction location.  The offset is     signed and counts in units of 4 bytes.  */  if (r_type == (unsigned int) R_PARISC_PCREL17F)    {      max_branch_offset = (1 << (17-1)) << 2;    }  else if (r_type == (unsigned int) R_PARISC_PCREL12F)    {      max_branch_offset = (1 << (12-1)) << 2;    }  else /* R_PARISC_PCREL22F.  */    {      max_branch_offset = (1 << (22-1)) << 2;    }  if (branch_offset + max_branch_offset >= 2*max_branch_offset)    {#if LONG_BRANCH_VIA_PLT      if (hash != NULL	  && hash->elf.dynindx != -1	  && hash->elf.plt.offset != (bfd_vma) -1	  && hash->elf.type != STT_PARISC_MILLI)	{	  /* If we are doing a shared link and find we need a long	     branch stub, then go via the .plt if possible.  */	  return hppa_stub_import;	}      else#endif	return hppa_stub_long_branch;    }  return hppa_stub_none;}/* Build one linker stub as defined by the stub hash table entry GEN_ENTRY.   IN_ARG contains the link info pointer.  */#define LDIL_R1		0x20200000	/* ldil  LR'XXX,%r1		*/#define BE_SR4_R1	0xe0202002	/* be,n  RR'XXX(%sr4,%r1)	*/#define BL_R1		0xe8200000	/* b,l   .+8,%r1		*/#define ADDIL_R1	0x28200000	/* addil LR'XXX,%r1,%r1		*/#define DEPI_R1		0xd4201c1e	/* depi  0,31,2,%r1		*/#define ADDIL_DP	0x2b600000	/* addil LR'XXX,%dp,%r1		*/#define LDW_R1_R21	0x48350000	/* ldw   RR'XXX(%sr0,%r1),%r21	*/#define BV_R0_R21	0xeaa0c000	/* bv    %r0(%r21)		*/#define LDW_R1_R19	0x48330000	/* ldw   RR'XXX(%sr0,%r1),%r19	*/#define ADDIL_R19	0x2a600000	/* addil LR'XXX,%r19,%r1	*/#define LDW_R1_DP	0x483b0000	/* ldw   RR'XXX(%sr0,%r1),%dp	*/#define LDSID_R21_R1	0x02a010a1	/* ldsid (%sr0,%r21),%r1	*/#define MTSP_R1		0x00011820	/* mtsp  %r1,%sr0		*/#define BE_SR0_R21	0xe2a00000	/* be    0(%sr0,%r21)		*/#define STW_RP		0x6bc23fd1	/* stw   %rp,-24(%sr0,%sp)	*/#define BL_RP		0xe8400002	/* b,l,n XXX,%rp		*/#define NOP		0x08000240	/* nop				*/#define LDW_RP		0x4bc23fd1	/* ldw   -24(%sr0,%sp),%rp	*/#define LDSID_RP_R1	0x004010a1	/* ldsid (%sr0,%rp),%r1		*/#define BE_SR0_RP	0xe0400002	/* be,n  0(%sr0,%rp)		*/#ifndef R19_STUBS#define R19_STUBS 1#endif#if R19_STUBS#define LDW_R1_DLT	LDW_R1_R19#else#define LDW_R1_DLT	LDW_R1_DP#endifstatic booleanhppa_build_one_stub (gen_entry, in_arg)     struct bfd_hash_entry *gen_entry;     PTR in_arg;{  struct elf32_hppa_stub_hash_entry *stub_entry;  struct bfd_link_info *info;  struct elf32_hppa_link_hash_table *hplink;  asection *stub_sec;  bfd *stub_bfd;  bfd_byte *loc;  bfd_vma sym_value;  bfd_vma insn;  bfd_vma off;  int val;  int size;  /* Massage our args to the form they really have.  */  stub_entry = (struct elf32_hppa_stub_hash_entry *) gen_entry;  info = (struct bfd_link_info *) in_arg;  hplink = hppa_link_hash_table (info);  stub_sec = stub_entry->stub_sec;  /* Make a note of the offset within the stubs for this entry.  */  stub_entry->stub_offset = stub_sec->_raw_size;  loc = stub_sec->contents + stub_entry->stub_offset;  stub_bfd = stub_sec->owner;  switch (stub_entry->stub_type)    {    case hppa_stub_long_branch:      /* Create the long branch.  A long branch is formed with "ldil"

⌨️ 快捷键说明

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