elf32-hppa.c

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

C
2,142
字号
      int need_entry;      r_symndx = ELF32_R_SYM (rel->r_info);      if (r_symndx < symtab_hdr->sh_info)	h = NULL;      else	h = ((struct elf32_hppa_link_hash_entry *)	     sym_hashes[r_symndx - symtab_hdr->sh_info]);      r_type = ELF32_R_TYPE (rel->r_info);      switch (r_type)	{	case R_PARISC_DLTIND14F:	case R_PARISC_DLTIND14R:	case R_PARISC_DLTIND21L:	  /* This symbol requires a global offset table entry.  */	  need_entry = NEED_GOT;	  /* Mark this section as containing PIC code.  */	  sec->flags |= SEC_HAS_GOT_REF;	  break;	case R_PARISC_PLABEL14R: /* "Official" procedure labels.  */	case R_PARISC_PLABEL21L:	case R_PARISC_PLABEL32:	  /* If the addend is non-zero, we break badly.  */	  if (rel->r_addend != 0)	    abort ();	  /* If we are creating a shared library, then we need to	     create a PLT entry for all PLABELs, because PLABELs with	     local symbols may be passed via a pointer to another	     object.  Additionally, output a dynamic relocation	     pointing to the PLT entry.	     For executables, the original 32-bit ABI allowed two	     different styles of PLABELs (function pointers):  For	     global functions, the PLABEL word points into the .plt	     two bytes past a (function address, gp) pair, and for	     local functions the PLABEL points directly at the	     function.  The magic +2 for the first type allows us to	     differentiate between the two.  As you can imagine, this	     is a real pain when it comes to generating code to call	     functions indirectly or to compare function pointers.	     We avoid the mess by always pointing a PLABEL into the	     .plt, even for local functions.  */	  need_entry = PLT_PLABEL | NEED_PLT | NEED_DYNREL;	  break;	case R_PARISC_PCREL12F:	  hplink->has_12bit_branch = 1;	  /* Fall thru.  */	case R_PARISC_PCREL17C:	case R_PARISC_PCREL17F:	  hplink->has_17bit_branch = 1;	  /* Fall thru.  */	case R_PARISC_PCREL22F:	  /* Function calls might need to go through the .plt, and	     might require long branch stubs.  */	  if (h == NULL)	    {	      /* We know local syms won't need a .plt entry, and if		 they need a long branch stub we can't guarantee that		 we can reach the stub.  So just flag an error later		 if we're doing a shared link and find we need a long		 branch stub.  */	      continue;	    }	  else	    {	      /* Global symbols will need a .plt entry if they remain		 global, and in most cases won't need a long branch		 stub.  Unfortunately, we have to cater for the case		 where a symbol is forced local by versioning, or due		 to symbolic linking, and we lose the .plt entry.  */	      need_entry = NEED_PLT | NEED_STUBREL;	      if (h->elf.type == STT_PARISC_MILLI)		need_entry = NEED_STUBREL;	    }	  break;	case R_PARISC_SEGBASE: /* Used to set segment base.  */	case R_PARISC_SEGREL32: /* Relative reloc, used for unwind.  */	case R_PARISC_PCREL14F: /* PC relative load/store.  */	case R_PARISC_PCREL14R:	case R_PARISC_PCREL17R: /* External branches.  */	case R_PARISC_PCREL21L: /* As above, and for load/store too.  */	  /* We don't need to propagate the relocation if linking a	     shared object since these are section relative.  */	  continue;	case R_PARISC_DPREL14F: /* Used for gp rel data load/store.  */	case R_PARISC_DPREL14R:	case R_PARISC_DPREL21L:	  if (info->shared)	    {	      (*_bfd_error_handler)		(_("%s: relocation %s can not be used when making a shared object; recompile with -fPIC"),		 bfd_get_filename (abfd),		 elf_hppa_howto_table[r_type].name);	      bfd_set_error (bfd_error_bad_value);	      return false;	    }	  /* Fall through.  */	case R_PARISC_DIR17F: /* Used for external branches.  */	case R_PARISC_DIR17R:	case R_PARISC_DIR14F: /* Used for load/store from absolute locn.  */	case R_PARISC_DIR14R:	case R_PARISC_DIR21L: /* As above, and for ext branches too.  */#if 1	  /* Help debug shared library creation.  Any of the above	     relocs can be used in shared libs, but they may cause	     pages to become unshared.  */	  if (info->shared)	    {	      (*_bfd_error_handler)		(_("%s: relocation %s should not be used when making a shared object; recompile with -fPIC"),		 bfd_get_filename (abfd),		 elf_hppa_howto_table[r_type].name);	    }	  /* Fall through.  */#endif	case R_PARISC_DIR32: /* .word relocs.  */	  /* We may want to output a dynamic relocation later.  */	  need_entry = NEED_DYNREL;	  break;	  /* This relocation describes the C++ object vtable hierarchy.	     Reconstruct it for later use during GC.  */	case R_PARISC_GNU_VTINHERIT:	  if (!_bfd_elf32_gc_record_vtinherit (abfd, sec,					       &h->elf, rel->r_offset))	    return false;	  continue;	  /* This relocation describes which C++ vtable entries are actually	     used.  Record for later use during GC.  */	case R_PARISC_GNU_VTENTRY:	  if (!_bfd_elf32_gc_record_vtentry (abfd, sec,					     &h->elf, rel->r_addend))	    return false;	  continue;	default:	  continue;	}      /* Now carry out our orders.  */      if (need_entry & NEED_GOT)	{	  /* Allocate space for a GOT entry, as well as a dynamic	     relocation for this entry.  */	  if (dynobj == NULL)	    hplink->root.dynobj = dynobj = abfd;	  if (hplink->sgot == NULL)	    {	      if (! elf32_hppa_create_dynamic_sections (dynobj, info))		return false;	    }	  if (h != NULL)	    {	      if (h->elf.got.refcount == -1)		{		  h->elf.got.refcount = 1;		  /* Make sure this symbol is output as a dynamic symbol.  */		  if (h->elf.dynindx == -1)		    {		      if (! bfd_elf32_link_record_dynamic_symbol (info,								  &h->elf))			return false;		    }		}	      else		h->elf.got.refcount += 1;	    }	  else	    {	      /* This is a global offset table entry for a local symbol.  */	      if (local_got_refcounts == NULL)		{		  size_t size;		  /* Allocate space for local got offsets and local		     plt offsets.  Done this way to save polluting		     elf_obj_tdata with another target specific		     pointer.  */		  size = symtab_hdr->sh_info * 2 * sizeof (bfd_signed_vma);		  local_got_refcounts = ((bfd_signed_vma *)					 bfd_alloc (abfd, size));		  if (local_got_refcounts == NULL)		    return false;		  elf_local_got_refcounts (abfd) = local_got_refcounts;		  memset (local_got_refcounts, -1, size);		}	      if (local_got_refcounts[r_symndx] == -1)		local_got_refcounts[r_symndx] = 1;	      else		local_got_refcounts[r_symndx] += 1;	    }	}      if (need_entry & NEED_PLT)	{	  /* If we are creating a shared library, and this is a reloc	     against a weak symbol or a global symbol in a dynamic	     object, then we will be creating an import stub and a	     .plt entry for the symbol.  Similarly, on a normal link	     to symbols defined in a dynamic object we'll need the	     import stub and a .plt entry.  We don't know yet whether	     the symbol is defined or not, so make an entry anyway and	     clean up later in adjust_dynamic_symbol.  */	  if ((sec->flags & SEC_ALLOC) != 0)	    {	      if (h != NULL)		{		  if (h->elf.plt.refcount == -1)		    {		      h->elf.plt.refcount = 1;		      h->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;		    }		  else		    h->elf.plt.refcount += 1;		  /* If this .plt entry is for a plabel, mark it so		     that adjust_dynamic_symbol will keep the entry		     even if it appears to be local.  */		  if (need_entry & PLT_PLABEL)		    h->plabel = 1;		}	      else if (need_entry & PLT_PLABEL)		{		  int indx;		  if (local_got_refcounts == NULL)		    {		      size_t size;		      /* Allocate space for local got offsets and local			 plt offsets.  */		      size = symtab_hdr->sh_info * 2 * sizeof (bfd_signed_vma);		      local_got_refcounts = ((bfd_signed_vma *)					     bfd_alloc (abfd, size));		      if (local_got_refcounts == NULL)			return false;		      elf_local_got_refcounts (abfd) = local_got_refcounts;		      memset (local_got_refcounts, -1, size);		    }		  indx = r_symndx + symtab_hdr->sh_info;		  if (local_got_refcounts[indx] == -1)		    local_got_refcounts[indx] = 1;		  else		    local_got_refcounts[indx] += 1;		}	    }	}      if (need_entry & (NEED_DYNREL | NEED_STUBREL))	{	  /* Flag this symbol as having a non-got, non-plt reference	     so that we generate copy relocs if it turns out to be	     dynamic.  */	  if (h != NULL)	    h->elf.elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;	  /* If we are creating a shared library then we need to copy	     the reloc into the shared library.  However, if we are	     linking with -Bsymbolic, we need only copy absolute	     relocs or relocs against symbols that are not defined in	     an object we are including in the link.  PC- or DP- or	     DLT-relative relocs against any local sym or global sym	     with DEF_REGULAR set, can be discarded.  At this point we	     have not seen all the input files, so it is possible that	     DEF_REGULAR is not set now but will be set later (it is	     never cleared).  We account for that possibility below by	     storing information in the reloc_entries field of the	     hash table entry.	     A similar situation to the -Bsymbolic case occurs when	     creating shared libraries and symbol visibility changes	     render the symbol local.	     As it turns out, all the relocs we will be creating here	     are absolute, so we cannot remove them on -Bsymbolic	     links or visibility changes anyway.  A STUB_REL reloc	     is absolute too, as in that case it is the reloc in the	     stub we will be creating, rather than copying the PCREL	     reloc in the branch.  */	  if ((sec->flags & SEC_ALLOC) != 0	      && info->shared#if RELATIVE_DYNAMIC_RELOCS	      && (!info->symbolic		  || is_absolute_reloc (r_type)		  || (h != NULL		      && ((h->elf.elf_link_hash_flags			   & ELF_LINK_HASH_DEF_REGULAR) == 0)))#endif	      )	    {	      boolean doit;	      asection *srel;	      srel = sreloc;	      if ((need_entry & NEED_STUBREL))		srel = stubreloc;	      /* Create a reloc section in dynobj and make room for		 this reloc.  */	      if (srel == NULL)		{		  char *name;		  if (dynobj == NULL)		    hplink->root.dynobj = dynobj = abfd;		  name = bfd_elf_string_from_elf_section		    (abfd,		     elf_elfheader (abfd)->e_shstrndx,		     elf_section_data (sec)->rel_hdr.sh_name);		  if (name == NULL)		    {		      (*_bfd_error_handler)			(_("Could not find relocation section for %s"),			 sec->name);		      bfd_set_error (bfd_error_bad_value);		      return false;		    }		  if ((need_entry & NEED_STUBREL))		    {		      size_t len = strlen (name) + sizeof (STUB_SUFFIX);		      char *newname = bfd_malloc (len);		      if (newname == NULL)			return false;		      strcpy (newname, name);		      strcpy (newname + len - sizeof (STUB_SUFFIX),			      STUB_SUFFIX);		      name = newname;		    }		  srel = bfd_get_section_by_name (dynobj, name);		  if (srel == NULL)		    {		      flagword flags;		      srel = bfd_make_section (dynobj, name);		      flags = (SEC_HAS_CONTENTS | SEC_READONLY			       | SEC_IN_MEMORY | SEC_LINKER_CREATED);		      if ((sec->flags & SEC_ALLOC) != 0)			flags |= SEC_ALLOC | SEC_LOAD;		      if (srel == NULL			  || !bfd_set_section_flags (dynobj, srel, flags)			  || !bfd_set_section_alignment (dynobj, srel, 2))			return false;		    }		  else if ((need_entry & NEED_STUBREL))		    free (name);		  if ((need_entry & NEED_STUBREL))		    stubreloc = srel;		  else		    sreloc = srel;		}#if ! LONG_BRANCH_PIC_IN_SHLIB	      /* If this is a function call, we only need one dynamic		 reloc for the stub as all calls to a particular		 function will go through the same stub.  Actually, a		 long branch stub needs two relocations, but we count		 on some intelligence on the part of the dynamic		 linker.  */	      if ((need_entry & NEED_STUBREL))		{		  doit = h->stub_reloc_sec != stubreloc;		  h->stub_reloc_sec = stubreloc;		}	      else#endif		doit = 1;	      if (doit)		{		  srel->_raw_size += sizeof (Elf32_External_Rela);#if ! LONG_BRANCH_PIC_IN_SHLIB || RELATIVE_DYNAMIC_RELOCS		  /* Keep track of relocations we have entered for		     this global symbol, so that we can discard them		     later if necessary.  */		  if (h != NULL		      && (0#if RELATIVE_DYNAMIC_RELOCS			  || ! is_absolute_reloc (rtype)#endif			  || (need_entry & NEED_STUBREL)))		    {		      struct elf32_hppa_dyn_reloc_entry *p;		      for (p = h->reloc_entries; p != NULL; p = p->next)			if (p->section == srel)			  break;		      if (p == NULL)			{			  p = ((struct elf32_hppa_dyn_reloc_entry *)			       bfd_alloc (dynobj, sizeof *p));			  if (p == NULL)			    return false;			  p->next = h->reloc_entries;			  h->reloc_entries = p;			  p->section = srel;			  p->count = 0;			}		      /* NEED_STUBREL and NEED_DYNREL are never both			 set.  Leave the count at zero for the			 NEED_STUBREL case as we only ever have one			 stub reloc per section per symbol, and this			 simplifies code in hppa_discard_copies.  */		      if (! (need_entry & NEED_STUBREL))			++p->count;		    }#endif		}

⌨️ 快捷键说明

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