elf64-hppa.c

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

C
2,237
字号
      /* Always create a DT_PLTGOT.  It actually has nothing to do with	 the PLT, it is how we communicate the __gp value of a load	 module to the dynamic linker.  */      if (! bfd_elf64_add_dynamic_entry (info, DT_HP_DLD_FLAGS, 0)	  || ! bfd_elf64_add_dynamic_entry (info, DT_PLTGOT, 0))	return false;      /* Add some entries to the .dynamic section.  We fill in the	 values later, in elf64_hppa_finish_dynamic_sections, but we	 must add the entries now so that we get the correct size for	 the .dynamic section.  The DT_DEBUG entry is filled in by the	 dynamic linker and used by the debugger.  */      if (! info->shared)	{	  if (! bfd_elf64_add_dynamic_entry (info, DT_DEBUG, 0)	      || ! bfd_elf64_add_dynamic_entry (info, DT_HP_DLD_HOOK, 0)	      || ! bfd_elf64_add_dynamic_entry (info, DT_HP_LOAD_MAP, 0))	    return false;	}      if (plt)	{	  if (! bfd_elf64_add_dynamic_entry (info, DT_PLTRELSZ, 0)	      || ! bfd_elf64_add_dynamic_entry (info, DT_PLTREL, DT_RELA)	      || ! bfd_elf64_add_dynamic_entry (info, DT_JMPREL, 0))	    return false;	}      if (relocs)	{	  if (! bfd_elf64_add_dynamic_entry (info, DT_RELA, 0)	      || ! bfd_elf64_add_dynamic_entry (info, DT_RELASZ, 0)	      || ! bfd_elf64_add_dynamic_entry (info, DT_RELAENT,						sizeof (Elf64_External_Rela)))	    return false;	}      if (reltext)	{	  if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0))	    return false;	  info->flags |= DF_TEXTREL;	}    }  return true;}/* Called after we have output the symbol into the dynamic symbol   table, but before we output the symbol into the normal symbol   table.   For some symbols we had to change their address when outputting   the dynamic symbol table.  We undo that change here so that   the symbols have their expected value in the normal symbol   table.  Ick.  */static booleanelf64_hppa_link_output_symbol_hook (abfd, info, name, sym, input_sec)     bfd *abfd ATTRIBUTE_UNUSED;     struct bfd_link_info *info;     const char *name;     Elf_Internal_Sym *sym;     asection *input_sec ATTRIBUTE_UNUSED;{  struct elf64_hppa_link_hash_table *hppa_info;  struct elf64_hppa_dyn_hash_entry *dyn_h;  /* We may be called with the file symbol or section symbols.     They never need munging, so it is safe to ignore them.  */  if (!name)    return true;  /* Get the PA dyn_symbol (if any) associated with NAME.  */  hppa_info = elf64_hppa_hash_table (info);  dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,				      name, false, false);  /* Function symbols for which we created .opd entries *may* have been     munged by finish_dynamic_symbol and have to be un-munged here.     Note that finish_dynamic_symbol sometimes turns dynamic symbols     into non-dynamic ones, so we initialize st_shndx to -1 in     mark_exported_functions and check to see if it was overwritten     here instead of just checking dyn_h->h->dynindx.  */  if (dyn_h && dyn_h->want_opd && dyn_h->st_shndx != -1)    {      /* Restore the saved value and section index.  */      sym->st_value = dyn_h->st_value;      sym->st_shndx = dyn_h->st_shndx;    }  return true;}/* Finish up dynamic symbol handling.  We set the contents of various   dynamic sections here.  */static booleanelf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)     bfd *output_bfd;     struct bfd_link_info *info;     struct elf_link_hash_entry *h;     Elf_Internal_Sym *sym;{  asection *stub, *splt, *sdlt, *sopd, *spltrel, *sdltrel;  struct elf64_hppa_link_hash_table *hppa_info;  struct elf64_hppa_dyn_hash_entry *dyn_h;  hppa_info = elf64_hppa_hash_table (info);  dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,				      h->root.root.string, false, false);  stub = hppa_info->stub_sec;  splt = hppa_info->plt_sec;  sdlt = hppa_info->dlt_sec;  sopd = hppa_info->opd_sec;  spltrel = hppa_info->plt_rel_sec;  sdltrel = hppa_info->dlt_rel_sec;  BFD_ASSERT (stub != NULL && splt != NULL	      && sopd != NULL && sdlt != NULL)  /* Incredible.  It is actually necessary to NOT use the symbol's real     value when building the dynamic symbol table for a shared library.     At least for symbols that refer to functions.     We will store a new value and section index into the symbol long     enough to output it into the dynamic symbol table, then we restore     the original values (in elf64_hppa_link_output_symbol_hook).  */  if (dyn_h && dyn_h->want_opd)    {      /* Save away the original value and section index so that we	 can restore them later.  */      dyn_h->st_value = sym->st_value;      dyn_h->st_shndx = sym->st_shndx;      /* For the dynamic symbol table entry, we want the value to be	 address of this symbol's entry within the .opd section.  */      sym->st_value = (dyn_h->opd_offset		       + sopd->output_offset		       + sopd->output_section->vma);      sym->st_shndx = _bfd_elf_section_from_bfd_section (output_bfd,							 sopd->output_section);    }  /* Initialize a .plt entry if requested.  */  if (dyn_h && dyn_h->want_plt      && elf64_hppa_dynamic_symbol_p (dyn_h->h, info))    {      bfd_vma value;      Elf_Internal_Rela rel;      /* We do not actually care about the value in the PLT entry	 if we are creating a shared library and the symbol is	 still undefined, we create a dynamic relocation to fill	 in the correct value.  */      if (info->shared && h->root.type == bfd_link_hash_undefined)	value = 0;      else	value = (h->root.u.def.value + h->root.u.def.section->vma);      /* Fill in the entry in the procedure linkage table.	 The format of a plt entry is	 <funcaddr> <__gp>.	 plt_offset is the offset within the PLT section at which to	 install the PLT entry.	 We are modifying the in-memory PLT contents here, so we do not add	 in the output_offset of the PLT section.  */      bfd_put_64 (splt->owner, value, splt->contents + dyn_h->plt_offset);      value = _bfd_get_gp_value (splt->output_section->owner);      bfd_put_64 (splt->owner, value, splt->contents + dyn_h->plt_offset + 0x8);      /* Create a dynamic IPLT relocation for this entry.	 We are creating a relocation in the output file's PLT section,	 which is included within the DLT secton.  So we do need to include	 the PLT's output_offset in the computation of the relocation's	 address.  */      rel.r_offset = (dyn_h->plt_offset + splt->output_offset		      + splt->output_section->vma);      rel.r_info = ELF64_R_INFO (h->dynindx, R_PARISC_IPLT);      rel.r_addend = 0;      bfd_elf64_swap_reloca_out (splt->output_section->owner, &rel,				 (((Elf64_External_Rela *)				   spltrel->contents)				  + spltrel->reloc_count));      spltrel->reloc_count++;    }  /* Initialize an external call stub entry if requested.  */  if (dyn_h && dyn_h->want_stub      && elf64_hppa_dynamic_symbol_p (dyn_h->h, info))    {      bfd_vma value;      int insn;      unsigned int max_offset;      /* Install the generic stub template.	 We are modifying the contents of the stub section, so we do not	 need to include the stub section's output_offset here.  */      memcpy (stub->contents + dyn_h->stub_offset, plt_stub, sizeof (plt_stub));      /* Fix up the first ldd instruction.	 We are modifying the contents of the STUB section in memory,	 so we do not need to include its output offset in this computation.	 Note the plt_offset value is the value of the PLT entry relative to	 the start of the PLT section.  These instructions will reference	 data relative to the value of __gp, which may not necessarily have	 the same address as the start of the PLT section.	 gp_offset contains the offset of __gp within the PLT section.  */      value = dyn_h->plt_offset - hppa_info->gp_offset;      insn = bfd_get_32 (stub->owner, stub->contents + dyn_h->stub_offset);      if (output_bfd->arch_info->mach >= 25)	{	  /* Wide mode allows 16 bit offsets.  */	  max_offset = 32768;	  insn &= ~ 0xfff1;	  insn |= re_assemble_16 (value);	}      else	{	  max_offset = 8192;	  insn &= ~ 0x3ff1;	  insn |= re_assemble_14 (value);	}      if ((value & 7) || value + max_offset >= 2*max_offset - 8)	{	  (*_bfd_error_handler) (_("stub entry for %s cannot load .plt, dp offset = %ld"),				 dyn_h->root.string,				 (long) value);	  return false;	}      bfd_put_32 (stub->owner, insn,		  stub->contents + dyn_h->stub_offset);      /* Fix up the second ldd instruction.  */      value += 8;      insn = bfd_get_32 (stub->owner, stub->contents + dyn_h->stub_offset + 8);      if (output_bfd->arch_info->mach >= 25)	{	  insn &= ~ 0xfff1;	  insn |= re_assemble_16 (value);	}      else	{	  insn &= ~ 0x3ff1;	  insn |= re_assemble_14 (value);	}      bfd_put_32 (stub->owner, insn,		  stub->contents + dyn_h->stub_offset + 8);    }  /* Millicode symbols should not be put in the dynamic     symbol table under any circumstances.  */  if (ELF_ST_TYPE (sym->st_info) == STT_PARISC_MILLI)    h->dynindx = -1;  return true;}/* The .opd section contains FPTRs for each function this file   exports.  Initialize the FPTR entries.  */static booleanelf64_hppa_finalize_opd (dyn_h, data)     struct elf64_hppa_dyn_hash_entry *dyn_h;     PTR data;{  struct bfd_link_info *info = (struct bfd_link_info *)data;  struct elf64_hppa_link_hash_table *hppa_info;  struct elf_link_hash_entry *h = dyn_h->h;  asection *sopd;  asection *sopdrel;  hppa_info = elf64_hppa_hash_table (info);  sopd = hppa_info->opd_sec;  sopdrel = hppa_info->opd_rel_sec;  if (h && dyn_h && dyn_h->want_opd)    {      bfd_vma value;      /* The first two words of an .opd entry are zero.	 We are modifying the contents of the OPD section in memory, so we	 do not need to include its output offset in this computation.  */      memset (sopd->contents + dyn_h->opd_offset, 0, 16);      value = (h->root.u.def.value	       + h->root.u.def.section->output_section->vma	       + h->root.u.def.section->output_offset);      /* The next word is the address of the function.  */      bfd_put_64 (sopd->owner, value, sopd->contents + dyn_h->opd_offset + 16);      /* The last word is our local __gp value.  */      value = _bfd_get_gp_value (sopd->output_section->owner);      bfd_put_64 (sopd->owner, value, sopd->contents + dyn_h->opd_offset + 24);    }  /* If we are generating a shared library, we must generate EPLT relocations     for each entry in the .opd, even for static functions (they may have     had their address taken).  */  if (info->shared && dyn_h && dyn_h->want_opd)    {      Elf64_Internal_Rela rel;      int dynindx;      /* We may need to do a relocation against a local symbol, in	 which case we have to look up it's dynamic symbol index off	 the local symbol hash table.  */      if (h && h->dynindx != -1)	dynindx = h->dynindx;      else	dynindx	  = _bfd_elf_link_lookup_local_dynindx (info, dyn_h->owner,						dyn_h->sym_indx);      /* The offset of this relocation is the absolute address of the	 .opd entry for this symbol.  */      rel.r_offset = (dyn_h->opd_offset + sopd->output_offset		      + sopd->output_section->vma);      /* If H is non-null, then we have an external symbol.	 It is imperative that we use a different dynamic symbol for the	 EPLT relocation if the symbol has global scope.	 In the dynamic symbol table, the function symbol will have a value	 which is address of the function's .opd entry.	 Thus, we can not use that dynamic symbol for the EPLT relocation	 (if we did, the data in the .opd would reference itself rather	 than the actual address of the function).  Instead we have to use	 a new dynamic symbol which has the same value as the original global	 function symbol.	 We prefix the original symbol with a "." and use the new symbol in	 the EPLT relocation.  This new symbol has already been recorded in	 the symbol table, we just have to look it up and use it.	 We do not have such problems with static functions because we do	 not make their addresses in the dynamic symbol table point to	 the .opd entry.  Ultimately this should be safe since a static	 function can not be directly referenced outside of its shared	 library.	 We do have to play similar games for FPTR relocations in shared	 libraries, including those for static symbols.  See the FPTR	 handling in elf64_hppa_finalize_dynreloc.  */      if (h)	{	  char *new_name;	  struct elf_link_hash_entry *nh;	  new_name = alloca (strlen (h->root.root.string) + 2);	  new_name[0] = '.';	  strcpy (new_name + 1, h->root.root.string);	  nh = elf_link_hash_lookup (elf_hash_table (info),				     new_name, false, false, false);	  /* All we really want from the new symbol is its dynamic	     symbol index.  */	  dynindx = nh->dynindx;	}      rel.r_addend = 0;      rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT);      bfd_elf64_swap_reloca_out (sopd->output_section->owner, &rel,				 (((Elf64_External_Rela *)				   sopdrel->contents)				  + sopdrel->reloc_count));      sopdrel->reloc_count++;    }  return true;}/* The .dlt section contains addresses for items referenced through the   dlt.  Note that we can have a DLTIND relocation for a local symbol, thus   we can not depend on finish_dynamic_symbol to initialize the .dlt.  */static booleanelf64_hppa_finalize_dlt (dyn_h, data)     struct elf64_hppa_dyn_hash_entry *dyn_h;     PTR data;{  struct bfd_link_info *info = (struct bfd_link_info *)data;  struct elf64_hppa_link_hash_table *hppa_info;  asection *sdlt, *sdltrel;  struct elf_link_hash_entry *h = dyn_h->h;  hppa_info = elf64_hppa_hash_table (info);  sdlt = hppa_info->dlt_sec;  sdltrel = hppa_info->dlt_rel_sec;  /* H/DYN_H may refer to a local variable and we know it's     address, so there is no need to create a relocation.  Just install     the proper value into the DLT, note this shortcut can not be     skipped when building a shared library.  */  if (! info->shared && h && dyn_h && dyn_h->want_dlt)    {      bfd_vma value;      /* If we had an LTOFF_FPTR style relocation we want the DLT entry	 to point to the FPTR entry in the .opd section.	 We include the OPD's output offset in this computation as	 we are referring to an absolute address in the resulting	 object file.  */      if (dyn_h->want_opd)	{	  value = (dyn_h->opd_offset		   + hppa_info->opd_sec->output_offset		   + hppa_info->opd_sec->output_section->vma);	}      else	{	  value = (h->root.u.def.value		   + h->root.u.def.section->output_offset);	  if (h->root.u.def.section->output_section)	    value += h->root.u.def.section->output_section->vma;	  else	    value += h->root.u.def.section->vma;	}      /* We do not need to include the output offset of the DLT section	 here because we are modifying the in-memory contents.  */      b

⌨️ 快捷键说明

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